summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.clang-format43
-rw-r--r--.github/CODEOWNERS1
-rw-r--r--.github/actions/godot-build/action.yml10
-rw-r--r--.github/actions/godot-cache-restore/action.yml3
-rw-r--r--.github/actions/godot-cache-save/action.yml2
-rw-r--r--.github/actions/godot-deps/action.yml3
-rw-r--r--.github/workflows/godot_cpp_test.yml3
-rw-r--r--.github/workflows/linux_builds.yml10
-rw-r--r--.gitignore10
-rw-r--r--.pre-commit-config.yaml7
-rw-r--r--COPYRIGHT.txt2
-rw-r--r--SConstruct121
-rw-r--r--core/config/project_settings.cpp27
-rw-r--r--core/core_bind.compat.inc5
-rw-r--r--core/core_bind.cpp34
-rw-r--r--core/core_bind.h18
-rw-r--r--core/core_constants.cpp1
-rw-r--r--core/debugger/engine_debugger.cpp2
-rw-r--r--core/debugger/local_debugger.cpp10
-rw-r--r--core/debugger/remote_debugger.cpp4
-rw-r--r--core/debugger/remote_debugger_peer.cpp2
-rw-r--r--core/extension/gdextension.cpp2
-rw-r--r--core/extension/gdextension_interface.cpp86
-rw-r--r--core/extension/gdextension_interface.h18
-rw-r--r--core/input/gamecontrollerdb.txt637
-rw-r--r--core/input/input.cpp2
-rw-r--r--core/input/input_event.cpp5
-rw-r--r--core/input/input_event.h5
-rw-r--r--core/input/input_map.cpp12
-rw-r--r--core/input/input_map.h9
-rw-r--r--core/io/dir_access.cpp4
-rw-r--r--core/io/file_access.compat.inc (renamed from modules/text_server_adv/thorvg_bounds_iterator.h)35
-rw-r--r--core/io/file_access.cpp25
-rw-r--r--core/io/file_access.h10
-rw-r--r--core/io/file_access_encrypted.cpp29
-rw-r--r--core/io/file_access_encrypted.h5
-rw-r--r--core/io/file_access_pack.cpp4
-rw-r--r--core/io/file_access_pack.h2
-rw-r--r--core/io/http_client.cpp4
-rw-r--r--core/io/http_client_tcp.cpp4
-rw-r--r--core/io/image.cpp234
-rw-r--r--core/io/image.h251
-rw-r--r--core/io/image_loader.cpp9
-rw-r--r--core/io/marshalls.cpp405
-rw-r--r--core/io/marshalls.h10
-rw-r--r--core/io/net_socket.h2
-rw-r--r--core/io/plist.cpp8
-rw-r--r--core/io/resource_loader.cpp27
-rw-r--r--core/io/resource_uid.cpp16
-rw-r--r--core/io/resource_uid.h4
-rw-r--r--core/io/stream_peer.cpp26
-rw-r--r--core/io/stream_peer.h2
-rw-r--r--core/io/translation_loader_po.cpp6
-rw-r--r--core/math/bvh_logic.inc1
-rw-r--r--core/math/bvh_misc.inc1
-rw-r--r--core/math/bvh_structs.inc1
-rw-r--r--core/math/projection.cpp322
-rw-r--r--core/math/vector4.cpp2
-rw-r--r--core/object/object.h1
-rw-r--r--core/object/worker_thread_pool.h8
-rw-r--r--core/os/os.cpp9
-rw-r--r--core/os/os.h17
-rw-r--r--core/register_core_types.cpp22
-rw-r--r--core/register_core_types.h1
-rw-r--r--core/string/node_path.cpp2
-rw-r--r--core/string/translation.cpp6
-rw-r--r--core/string/translation_po.cpp8
-rw-r--r--core/string/translation_server.compat.inc (renamed from modules/text_server_adv/thorvg_bounds_iterator.cpp)45
-rw-r--r--core/string/translation_server.cpp142
-rw-r--r--core/string/translation_server.h28
-rw-r--r--core/string/ustring.cpp40
-rw-r--r--core/templates/a_hash_map.h5
-rw-r--r--core/variant/callable.cpp25
-rw-r--r--core/variant/callable.h6
-rw-r--r--core/variant/callable_bind.cpp67
-rw-r--r--core/variant/callable_bind.h6
-rw-r--r--core/variant/variant.cpp19
-rw-r--r--core/variant/variant.h3
-rw-r--r--core/variant/variant_call.cpp62
-rw-r--r--doc/classes/@GlobalScope.xml111
-rw-r--r--doc/classes/AABB.xml6
-rw-r--r--doc/classes/AStar2D.xml2
-rw-r--r--doc/classes/AnimatedSprite2D.xml2
-rw-r--r--doc/classes/AnimatedSprite3D.xml2
-rw-r--r--doc/classes/AnimationLibrary.xml6
-rw-r--r--doc/classes/AnimationMixer.xml44
-rw-r--r--doc/classes/AnimationNodeAnimation.xml4
-rw-r--r--doc/classes/AnimationNodeTimeSeek.xml5
-rw-r--r--doc/classes/Area2D.xml4
-rw-r--r--doc/classes/Area3D.xml4
-rw-r--r--doc/classes/AudioEffectSpectrumAnalyzer.xml2
-rw-r--r--doc/classes/AudioEffectSpectrumAnalyzerInstance.xml2
-rw-r--r--doc/classes/AudioStream.xml2
-rw-r--r--doc/classes/AudioStreamPlayer.xml1
-rw-r--r--doc/classes/Basis.xml2
-rw-r--r--doc/classes/Button.xml6
-rw-r--r--doc/classes/CPUParticles2D.xml2
-rw-r--r--doc/classes/Callable.xml19
-rw-r--r--doc/classes/CallbackTweener.xml2
-rw-r--r--doc/classes/CameraAttributes.xml4
-rw-r--r--doc/classes/CanvasItem.xml5
-rw-r--r--doc/classes/CharacterBody2D.xml2
-rw-r--r--doc/classes/CodeEdit.xml62
-rw-r--r--doc/classes/CollisionShape3D.xml6
-rw-r--r--doc/classes/Control.xml46
-rw-r--r--doc/classes/Curve3D.xml3
-rw-r--r--doc/classes/DirAccess.xml8
-rw-r--r--doc/classes/DisplayServer.xml2
-rw-r--r--doc/classes/EditorImportPlugin.xml2
-rw-r--r--doc/classes/EditorInterface.xml6
-rw-r--r--doc/classes/EditorNode3DGizmoPlugin.xml2
-rw-r--r--doc/classes/EditorPlugin.xml2
-rw-r--r--doc/classes/EditorResourcePreviewGenerator.xml2
-rw-r--r--doc/classes/EditorScenePostImport.xml2
-rw-r--r--doc/classes/EditorScript.xml2
-rw-r--r--doc/classes/EditorSettings.xml7
-rw-r--r--doc/classes/EditorSpinSlider.xml5
-rw-r--r--doc/classes/EditorToaster.xml34
-rw-r--r--doc/classes/EditorTranslationParserPlugin.xml11
-rw-r--r--doc/classes/Engine.xml16
-rw-r--r--doc/classes/Environment.xml3
-rw-r--r--doc/classes/FileAccess.xml16
-rw-r--r--doc/classes/GPUParticles2D.xml2
-rw-r--r--doc/classes/GPUParticles3D.xml4
-rw-r--r--doc/classes/GPUParticlesCollision3D.xml4
-rw-r--r--doc/classes/GeometryInstance3D.xml16
-rw-r--r--doc/classes/HTTPClient.xml6
-rw-r--r--doc/classes/HTTPRequest.xml6
-rw-r--r--doc/classes/Image.xml1
-rw-r--r--doc/classes/ItemList.xml2
-rw-r--r--doc/classes/LightmapGI.xml4
-rw-r--r--doc/classes/LookAtModifier3D.xml162
-rw-r--r--doc/classes/MainLoop.xml2
-rw-r--r--doc/classes/MeshInstance3D.xml2
-rw-r--r--doc/classes/MultiplayerAPI.xml2
-rw-r--r--doc/classes/MultiplayerAPIExtension.xml10
-rw-r--r--doc/classes/Node.xml4
-rw-r--r--doc/classes/NodePath.xml2
-rw-r--r--doc/classes/OS.xml68
-rw-r--r--doc/classes/Object.xml8
-rw-r--r--doc/classes/PackedInt64Array.xml2
-rw-r--r--doc/classes/PackedScene.xml4
-rw-r--r--doc/classes/PackedVector4Array.xml1
-rw-r--r--doc/classes/PacketPeerUDP.xml27
-rw-r--r--doc/classes/PhysicalBone3D.xml6
-rw-r--r--doc/classes/PopupMenu.xml3
-rw-r--r--doc/classes/PrimitiveMesh.xml3
-rw-r--r--doc/classes/ProjectSettings.xml10
-rw-r--r--doc/classes/Projection.xml12
-rw-r--r--doc/classes/RDTextureFormat.xml2
-rw-r--r--doc/classes/RDTextureView.xml2
-rw-r--r--doc/classes/Range.xml2
-rw-r--r--doc/classes/RenderData.xml2
-rw-r--r--doc/classes/RenderSceneBuffersRD.xml2
-rw-r--r--doc/classes/RenderingServer.xml17
-rw-r--r--doc/classes/Resource.xml2
-rw-r--r--doc/classes/ResourceImporterTexture.xml6
-rw-r--r--doc/classes/RetargetModifier3D.xml34
-rw-r--r--doc/classes/RichTextLabel.xml6
-rw-r--r--doc/classes/RigidBody2D.xml6
-rw-r--r--doc/classes/RigidBody3D.xml6
-rw-r--r--doc/classes/Skeleton3D.xml5
-rw-r--r--doc/classes/SkeletonModification2DTwoBoneIK.xml2
-rw-r--r--doc/classes/SplitContainer.xml2
-rw-r--r--doc/classes/StreamPeer.xml13
-rw-r--r--doc/classes/String.xml16
-rw-r--r--doc/classes/StringName.xml43
-rw-r--r--doc/classes/StyleBoxTexture.xml6
-rw-r--r--doc/classes/SubViewportContainer.xml4
-rw-r--r--doc/classes/SurfaceTool.xml2
-rw-r--r--doc/classes/SyntaxHighlighter.xml9
-rw-r--r--doc/classes/TextEdit.xml58
-rw-r--r--doc/classes/TextureProgressBar.xml1
-rw-r--r--doc/classes/TileMapLayer.xml2
-rw-r--r--doc/classes/TouchScreenButton.xml2
-rw-r--r--doc/classes/Transform3D.xml2
-rw-r--r--doc/classes/TranslationServer.xml3
-rw-r--r--doc/classes/Tween.xml36
-rw-r--r--doc/classes/Vector2.xml4
-rw-r--r--doc/classes/Vector2i.xml4
-rw-r--r--doc/classes/Vector3.xml6
-rw-r--r--doc/classes/Vector3i.xml6
-rw-r--r--doc/classes/Vector4.xml8
-rw-r--r--doc/classes/Vector4i.xml8
-rw-r--r--doc/classes/Viewport.xml5
-rw-r--r--doc/classes/VisualShaderNodeColorFunc.xml27
-rw-r--r--doc/classes/Window.xml3
-rw-r--r--doc/classes/XRCamera3D.xml2
-rw-r--r--doc/classes/XRController3D.xml4
-rw-r--r--doc/classes/XRNode3D.xml2
-rwxr-xr-xdoc/tools/make_rst.py4
-rw-r--r--drivers/alsa/audio_driver_alsa.cpp2
-rw-r--r--drivers/d3d12/rendering_context_driver_d3d12.cpp6
-rw-r--r--drivers/d3d12/rendering_context_driver_d3d12.h18
-rw-r--r--drivers/d3d12/rendering_device_driver_d3d12.cpp45
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp86
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.h38
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp4
-rw-r--r--drivers/gles3/shaders/canvas.glsl57
-rw-r--r--drivers/gles3/shaders/canvas_uniforms_inc.glsl37
-rw-r--r--drivers/gles3/shaders/scene.glsl22
-rw-r--r--drivers/gles3/shaders/sky.glsl6
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp4
-rw-r--r--drivers/gles3/storage/mesh_storage.h1
-rw-r--r--drivers/metal/rendering_context_driver_metal.h2
-rw-r--r--drivers/metal/rendering_context_driver_metal.mm2
-rw-r--r--drivers/metal/rendering_device_driver_metal.h1
-rw-r--r--drivers/metal/rendering_device_driver_metal.mm27
-rw-r--r--drivers/unix/file_access_unix.cpp2
-rw-r--r--drivers/unix/file_access_unix_pipe.cpp2
-rw-r--r--drivers/unix/ip_unix.cpp75
-rw-r--r--drivers/unix/ip_unix.h6
-rw-r--r--drivers/unix/net_socket_unix.cpp (renamed from drivers/unix/net_socket_posix.cpp)328
-rw-r--r--drivers/unix/net_socket_unix.h (renamed from drivers/unix/net_socket_posix.h)80
-rw-r--r--drivers/unix/os_unix.cpp97
-rw-r--r--drivers/unix/os_unix.h6
-rw-r--r--drivers/vulkan/rendering_device_driver_vulkan.cpp9
-rw-r--r--drivers/windows/dir_access_windows.cpp4
-rw-r--r--drivers/windows/file_access_windows.cpp2
-rw-r--r--drivers/windows/ip_windows.cpp164
-rw-r--r--drivers/windows/ip_windows.h (renamed from modules/text_server_fb/thorvg_bounds_iterator.h)36
-rw-r--r--drivers/windows/net_socket_winsock.cpp613
-rw-r--r--drivers/windows/net_socket_winsock.h102
-rw-r--r--editor/animation_bezier_editor.cpp4
-rw-r--r--editor/animation_track_editor.cpp91
-rw-r--r--editor/animation_track_editor.h2
-rw-r--r--editor/connections_dialog.cpp2
-rw-r--r--editor/create_dialog.cpp4
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_parser.cpp2
-rw-r--r--editor/debugger/editor_debugger_node.cpp10
-rw-r--r--editor/debugger/editor_debugger_tree.cpp2
-rw-r--r--editor/debugger/editor_performance_profiler.cpp3
-rw-r--r--editor/debugger/script_editor_debugger.cpp1
-rw-r--r--editor/dependency_editor.cpp2
-rw-r--r--editor/directory_create_dialog.cpp2
-rw-r--r--editor/doc_tools.cpp17
-rw-r--r--editor/editor_asset_installer.cpp8
-rw-r--r--editor/editor_file_system.cpp3
-rw-r--r--editor/editor_folding.cpp2
-rw-r--r--editor/editor_help.cpp10
-rw-r--r--editor/editor_help_search.cpp4
-rw-r--r--editor/editor_inspector.cpp32
-rw-r--r--editor/editor_interface.cpp74
-rw-r--r--editor/editor_interface.h4
-rw-r--r--editor/editor_node.cpp41
-rw-r--r--editor/editor_node.h1
-rw-r--r--editor/editor_properties.cpp13
-rw-r--r--editor/editor_properties_array_dict.cpp20
-rw-r--r--editor/editor_sectioned_inspector.cpp4
-rw-r--r--editor/editor_settings.cpp1
-rw-r--r--editor/editor_settings_dialog.cpp4
-rw-r--r--editor/editor_translation_parser.cpp17
-rw-r--r--editor/editor_translation_parser.h2
-rw-r--r--editor/engine_update_label.cpp4
-rw-r--r--editor/event_listener_line_edit.cpp2
-rw-r--r--editor/export/editor_export.cpp5
-rw-r--r--editor/export/editor_export_platform.cpp108
-rw-r--r--editor/export/editor_export_platform.h14
-rw-r--r--editor/export/editor_export_platform_pc.cpp4
-rw-r--r--editor/export/editor_export_preset.cpp9
-rw-r--r--editor/export/editor_export_preset.h4
-rw-r--r--editor/export/project_export.cpp36
-rw-r--r--editor/export/project_export.h3
-rw-r--r--editor/filesystem_dock.cpp134
-rw-r--r--editor/filesystem_dock.h5
-rw-r--r--editor/gui/editor_file_dialog.cpp35
-rw-r--r--editor/gui/editor_file_dialog.h1
-rw-r--r--editor/gui/editor_spin_slider.cpp6
-rw-r--r--editor/gui/editor_toaster.cpp8
-rw-r--r--editor/gui/editor_toaster.h1
-rw-r--r--editor/gui/scene_tree_editor.cpp13
-rw-r--r--editor/icons/FlipWinding.svg1
-rw-r--r--editor/icons/LookAtModifier3D.svg1
-rw-r--r--editor/icons/RetargetModifier3D.svg1
-rw-r--r--editor/import/3d/post_import_plugin_skeleton_renamer.cpp2
-rw-r--r--editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp227
-rw-r--r--editor/import/3d/post_import_plugin_skeleton_track_organizer.cpp42
-rw-r--r--editor/import/3d/resource_importer_scene.cpp1
-rw-r--r--editor/import/resource_importer_imagefont.cpp2
-rw-r--r--editor/import/resource_importer_texture.cpp38
-rw-r--r--editor/input_event_configuration_dialog.cpp15
-rw-r--r--editor/localization_editor.cpp6
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp33
-rw-r--r--editor/plugins/animation_library_editor.cpp203
-rw-r--r--editor/plugins/animation_library_editor.h7
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp3
-rw-r--r--editor/plugins/animation_state_machine_editor.h1
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp299
-rw-r--r--editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp75
-rw-r--r--editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.h2
-rw-r--r--editor/plugins/lightmap_gi_editor_plugin.cpp12
-rw-r--r--editor/plugins/navigation_obstacle_3d_editor_plugin.cpp889
-rw-r--r--editor/plugins/navigation_obstacle_3d_editor_plugin.h110
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp7
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp10
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp119
-rw-r--r--editor/plugins/path_3d_editor_plugin.h4
-rw-r--r--editor/plugins/plugin_config_dialog.cpp2
-rw-r--r--editor/plugins/script_editor_plugin.cpp24
-rw-r--r--editor/plugins/script_text_editor.cpp7
-rw-r--r--editor/plugins/theme_editor_plugin.cpp2
-rw-r--r--editor/plugins/theme_editor_preview.cpp6
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp4
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp116
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h12
-rw-r--r--editor/plugins/voxel_gi_editor_plugin.cpp10
-rw-r--r--editor/plugins/voxel_gi_editor_plugin.h4
-rw-r--r--editor/pot_generator.cpp48
-rw-r--r--editor/pot_generator.h3
-rw-r--r--editor/project_converter_3_to_4.cpp6
-rw-r--r--editor/project_manager.cpp19
-rw-r--r--editor/project_settings_editor.cpp3
-rw-r--r--editor/register_editor_types.cpp2
-rw-r--r--editor/script_create_dialog.cpp3
-rw-r--r--editor/shader_create_dialog.cpp5
-rw-r--r--editor/themes/editor_theme_manager.cpp1
-rw-r--r--main/main.cpp114
-rw-r--r--main/performance.cpp4
-rw-r--r--methods.py420
-rw-r--r--misc/dist/html/editor.html34
-rw-r--r--misc/dist/html/full-size.html10
-rw-r--r--misc/extension_api_validation/4.3-stable.expected51
-rw-r--r--misc/utility/.clang-format-glsl5
-rw-r--r--modules/SCsub5
-rw-r--r--modules/basis_universal/image_compress_basisu.cpp14
-rw-r--r--modules/betsy/CrossPlatformSettings_piece_all.glsl1
-rw-r--r--modules/betsy/UavCrossPlatform_piece_all.glsl1
-rw-r--r--modules/dds/texture_loader_dds.cpp9
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml14
-rw-r--r--modules/gdscript/doc_classes/GDScript.xml3
-rw-r--r--modules/gdscript/editor/gdscript_docgen.cpp2
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp4
-rw-r--r--modules/gdscript/editor/gdscript_translation_parser_plugin.cpp94
-rw-r--r--modules/gdscript/editor/gdscript_translation_parser_plugin.h15
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp97
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp21
-rw-r--r--modules/gdscript/gdscript_editor.cpp49
-rw-r--r--modules/gdscript/gdscript_parser.cpp4
-rw-r--r--modules/gdscript/gdscript_parser.h2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.gd28
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.out25
-rw-r--r--modules/gdscript/tests/scripts/completion/argument_options/argument_options.tscn13
-rw-r--r--modules/gdscript/tests/scripts/completion/argument_options/play_inferred.cfg6
-rw-r--r--modules/gdscript/tests/scripts/completion/argument_options/play_inferred.gd5
-rw-r--r--modules/gdscript/tests/scripts/completion/argument_options/play_typed.cfg6
-rw-r--r--modules/gdscript/tests/scripts/completion/argument_options/play_typed.gd5
-rw-r--r--modules/gdscript/tests/scripts/completion/argument_options/play_untyped.cfg6
-rw-r--r--modules/gdscript/tests/scripts/completion/argument_options/play_untyped.gd5
-rw-r--r--modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/common/identifiers_in_call.cfg8
-rw-r--r--modules/gdscript/tests/scripts/completion/common/identifiers_in_function_body.cfg8
-rw-r--r--modules/gdscript/tests/scripts/completion/common/identifiers_in_unclosed_call.cfg8
-rw-r--r--modules/gdscript/tests/scripts/completion/common/no_completion_in_string.cfg10
-rw-r--r--modules/gdscript/tests/scripts/completion/common/self.cfg8
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local/local.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_infered/local_infered.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/class_local_infered_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/native_local_infered_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member/member.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_infered/member_infered.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/class_member_infered_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/native_member_infered_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg6
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/infered.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/no_type.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/typehint.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/typehint_broad.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/infered.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/no_type.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/typehint.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/typehint_broad.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.cfg4
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/division_by_zero.gd3
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/division_by_zero.out6
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.gd3
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.out6
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/stringify.gd10
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/stringify.out11
-rw-r--r--modules/gltf/doc_classes/GLTFAccessor.xml6
-rw-r--r--modules/gltf/doc_classes/GLTFState.xml2
-rw-r--r--modules/gltf/editor/editor_scene_importer_blend.cpp4
-rw-r--r--modules/gltf/gltf_document.cpp2
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.cpp25
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp115
-rw-r--r--modules/lightmapper_rd/lm_common_inc.glsl1
-rw-r--r--modules/mbedtls/stream_peer_mbedtls.cpp62
-rw-r--r--modules/mono/csharp_script.cpp2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ExportDiagnosticsTests.cs27
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertiesGeneratorTests.cs9
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/EventSignals_ScriptSignals.generated.cs4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0108_ScriptProperties.generated.cs48
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0109_ScriptProperties.generated.cs48
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0110_ScriptProperties.generated.cs48
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedToolButtons_ScriptProperties.generated.cs48
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0108.cs8
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0109.cs9
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0110.cs9
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedToolButtons.cs12
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/AnalyzerReleases.Unshipped.md3
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs30
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs6
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs3
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs99
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs6
-rw-r--r--modules/mono/editor/bindings_generator.cpp59
-rw-r--r--modules/mono/editor/code_completion.cpp2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportToolButtonAttribute.cs33
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj1
-rw-r--r--modules/mono/utils/path_utils.cpp2
-rw-r--r--modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml4
-rw-r--r--modules/multiplayer/editor/replication_editor.cpp4
-rw-r--r--modules/multiplayer/multiplayer_spawner.cpp10
-rw-r--r--modules/multiplayer/multiplayer_spawner.h1
-rw-r--r--modules/navigation/2d/nav_mesh_generator_2d.cpp57
-rw-r--r--modules/navigation/nav_map.cpp45
-rw-r--r--modules/navigation/nav_map.h28
-rw-r--r--modules/navigation/nav_utils.h13
-rw-r--r--modules/noise/doc_classes/FastNoiseLite.xml2
-rw-r--r--modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml2
-rw-r--r--modules/openxr/openxr_api.cpp5
-rw-r--r--modules/openxr/openxr_interface.cpp10
-rw-r--r--modules/openxr/openxr_interface.h3
-rw-r--r--modules/regex/doc_classes/RegEx.xml4
-rw-r--r--modules/svg/image_loader_svg.cpp2
-rw-r--r--modules/text_server_adv/thorvg_svg_in_ot.cpp123
-rw-r--r--modules/text_server_adv/thorvg_svg_in_ot.h2
-rw-r--r--modules/text_server_fb/thorvg_svg_in_ot.cpp125
-rw-r--r--modules/text_server_fb/thorvg_svg_in_ot.h2
-rw-r--r--modules/upnp/SCsub2
-rw-r--r--modules/upnp/register_types.cpp14
-rw-r--r--modules/upnp/upnp.cpp299
-rw-r--r--modules/upnp/upnp.h61
-rw-r--r--modules/upnp/upnp_device.cpp126
-rw-r--r--modules/upnp/upnp_device.h57
-rw-r--r--modules/upnp/upnp_device_miniupnp.cpp153
-rw-r--r--modules/upnp/upnp_device_miniupnp.h83
-rw-r--r--modules/upnp/upnp_miniupnp.cpp334
-rw-r--r--modules/upnp/upnp_miniupnp.h93
-rw-r--r--modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml2
-rw-r--r--modules/websocket/doc_classes/WebSocketPeer.xml6
-rw-r--r--modules/websocket/packet_buffer.h8
-rw-r--r--modules/websocket/websocket_peer.cpp14
-rw-r--r--modules/websocket/websocket_peer.h6
-rw-r--r--modules/websocket/wsl_peer.cpp123
-rw-r--r--modules/websocket/wsl_peer.h17
-rw-r--r--platform/android/detect.py19
-rw-r--r--platform/android/doc_classes/EditorExportPlatformAndroid.xml15
-rw-r--r--platform/android/export/export.cpp18
-rw-r--r--platform/android/export/export_plugin.cpp30
-rw-r--r--platform/android/export/export_plugin.h6
-rw-r--r--platform/android/export/gradle_export_util.cpp23
-rw-r--r--platform/android/export/gradle_export_util.h3
-rw-r--r--platform/android/java/app/res/values/themes.xml4
-rw-r--r--platform/android/java/editor/build.gradle2
-rw-r--r--platform/android/java/editor/src/main/res/values/themes.xml3
-rw-r--r--platform/android/java/lib/build.gradle2
-rw-r--r--platform/android/net_socket_android.cpp8
-rw-r--r--platform/android/net_socket_android.h4
-rw-r--r--platform/linuxbsd/detect.py12
-rw-r--r--platform/linuxbsd/freedesktop_portal_desktop.cpp4
-rw-r--r--platform/linuxbsd/wayland/wayland_thread.cpp6
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.c126
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.h126
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xext-so_wrap.c34
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xext-so_wrap.h35
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.c16
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.h16
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.c76
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.h76
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xlib-so_wrap.c1238
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xlib-so_wrap.h1225
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.c148
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.h148
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.c96
-rw-r--r--platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.h96
-rw-r--r--platform/macos/SCsub4
-rw-r--r--platform/macos/detect.py5
-rw-r--r--platform/macos/export/export_plugin.cpp4
-rw-r--r--platform/macos/godot_open_save_delegate.mm2
-rw-r--r--platform/macos/os_macos.h2
-rw-r--r--platform/macos/os_macos.mm9
-rw-r--r--platform/web/SCsub11
-rw-r--r--platform/web/api/api.cpp2
-rw-r--r--platform/web/detect.py2
-rw-r--r--platform/web/doc_classes/EditorExportPlatformWeb.xml8
-rw-r--r--platform/web/editor/web_tools_editor_plugin.cpp (renamed from platform/web/api/web_tools_editor_plugin.cpp)6
-rw-r--r--platform/web/editor/web_tools_editor_plugin.h (renamed from platform/web/api/web_tools_editor_plugin.h)4
-rw-r--r--platform/web/emscripten_helpers.py7
-rw-r--r--platform/web/export/export_plugin.cpp8
-rw-r--r--platform/web/js/engine/config.js2
-rw-r--r--platform/web/js/engine/engine.js6
-rw-r--r--platform/web/js/libs/library_godot_input.js104
-rw-r--r--platform/web/js/libs/library_godot_os.js25
-rw-r--r--platform/web/package-lock.json554
-rw-r--r--platform/web/package.json12
-rw-r--r--platform/web/web_main.cpp8
-rw-r--r--platform/windows/SCsub13
-rw-r--r--platform/windows/display_server_windows.cpp19
-rw-r--r--platform/windows/display_server_windows.h5
-rw-r--r--platform/windows/godot.natvis171
-rw-r--r--platform/windows/os_windows.cpp283
-rw-r--r--platform/windows/os_windows.h14
-rw-r--r--platform/windows/tts_windows.cpp10
-rw-r--r--platform/windows/tts_windows.h4
-rw-r--r--platform/windows/windows_terminal_logger.cpp4
-rw-r--r--platform_methods.py7
-rw-r--r--pyproject.toml100
-rw-r--r--scene/2d/audio_stream_player_2d.cpp2
-rw-r--r--scene/2d/cpu_particles_2d.cpp6
-rw-r--r--scene/2d/gpu_particles_2d.cpp5
-rw-r--r--scene/2d/light_2d.cpp2
-rw-r--r--scene/2d/navigation_obstacle_2d.cpp56
-rw-r--r--scene/2d/navigation_obstacle_2d.h3
-rw-r--r--scene/2d/physics/rigid_body_2d.cpp2
-rw-r--r--scene/2d/tile_map.cpp2
-rw-r--r--scene/3d/audio_stream_player_3d.cpp2
-rw-r--r--scene/3d/cpu_particles_3d.cpp6
-rw-r--r--scene/3d/gpu_particles_3d.cpp6
-rw-r--r--scene/3d/lightmap_gi.cpp8
-rw-r--r--scene/3d/lightmap_gi.h2
-rw-r--r--scene/3d/lightmapper.h1
-rw-r--r--scene/3d/look_at_modifier_3d.cpp835
-rw-r--r--scene/3d/look_at_modifier_3d.h205
-rw-r--r--scene/3d/mesh_instance_3d.cpp15
-rw-r--r--scene/3d/navigation_obstacle_3d.cpp337
-rw-r--r--scene/3d/navigation_obstacle_3d.h12
-rw-r--r--scene/3d/node_3d.cpp4
-rw-r--r--scene/3d/physics/collision_shape_3d.cpp98
-rw-r--r--scene/3d/physics/collision_shape_3d.h22
-rw-r--r--scene/3d/physics/rigid_body_3d.cpp2
-rw-r--r--scene/3d/retarget_modifier_3d.cpp441
-rw-r--r--scene/3d/retarget_modifier_3d.h110
-rw-r--r--scene/3d/skeleton_3d.cpp12
-rw-r--r--scene/3d/skeleton_3d.h2
-rw-r--r--scene/3d/skeleton_modifier_3d.cpp16
-rw-r--r--scene/3d/skeleton_modifier_3d.h1
-rw-r--r--scene/3d/visual_instance_3d.cpp48
-rw-r--r--scene/3d/visual_instance_3d.h11
-rw-r--r--scene/3d/voxel_gi.cpp49
-rw-r--r--scene/3d/voxel_gi.h4
-rw-r--r--scene/3d/voxelizer.cpp71
-rw-r--r--scene/3d/voxelizer.h14
-rw-r--r--scene/animation/animation_blend_tree.cpp40
-rw-r--r--scene/animation/animation_blend_tree.h12
-rw-r--r--scene/animation/animation_mixer.cpp189
-rw-r--r--scene/animation/animation_mixer.h6
-rw-r--r--scene/animation/animation_player.cpp42
-rw-r--r--scene/animation/animation_player.h16
-rw-r--r--scene/animation/animation_tree.cpp4
-rw-r--r--scene/animation/animation_tree.h2
-rw-r--r--scene/animation/root_motion_view.cpp5
-rw-r--r--scene/audio/audio_stream_player.cpp2
-rw-r--r--scene/gui/code_edit.cpp4
-rw-r--r--scene/gui/color_mode.h2
-rw-r--r--scene/gui/color_picker.cpp78
-rw-r--r--scene/gui/color_picker.h45
-rw-r--r--scene/gui/file_dialog.cpp37
-rw-r--r--scene/gui/file_dialog.h1
-rw-r--r--scene/gui/line_edit.cpp14
-rw-r--r--scene/gui/option_button.cpp2
-rw-r--r--scene/gui/popup_menu.cpp18
-rw-r--r--scene/gui/rich_text_label.cpp44
-rw-r--r--scene/gui/rich_text_label.h3
-rw-r--r--scene/gui/spin_box.cpp44
-rw-r--r--scene/gui/spin_box.h3
-rw-r--r--scene/gui/subviewport_container.cpp12
-rw-r--r--scene/gui/subviewport_container.h5
-rw-r--r--scene/gui/text_edit.cpp13
-rw-r--r--scene/gui/texture_progress_bar.cpp9
-rw-r--r--scene/main/http_request.cpp2
-rw-r--r--scene/main/missing_node.cpp14
-rw-r--r--scene/main/node.cpp9
-rw-r--r--scene/main/viewport.cpp36
-rw-r--r--scene/main/window.cpp5
-rw-r--r--scene/main/window.h1
-rw-r--r--scene/property_utils.cpp2
-rw-r--r--scene/register_scene_types.cpp4
-rw-r--r--scene/resources/3d/box_shape_3d.cpp20
-rw-r--r--scene/resources/3d/box_shape_3d.h1
-rw-r--r--scene/resources/3d/capsule_shape_3d.cpp19
-rw-r--r--scene/resources/3d/capsule_shape_3d.h3
-rw-r--r--scene/resources/3d/concave_polygon_shape_3d.cpp18
-rw-r--r--scene/resources/3d/concave_polygon_shape_3d.h3
-rw-r--r--scene/resources/3d/convex_polygon_shape_3d.cpp39
-rw-r--r--scene/resources/3d/convex_polygon_shape_3d.h3
-rw-r--r--scene/resources/3d/cylinder_shape_3d.cpp19
-rw-r--r--scene/resources/3d/cylinder_shape_3d.h3
-rw-r--r--scene/resources/3d/height_map_shape_3d.cpp55
-rw-r--r--scene/resources/3d/height_map_shape_3d.h2
-rw-r--r--scene/resources/3d/primitive_meshes.cpp169
-rw-r--r--scene/resources/3d/separation_ray_shape_3d.cpp5
-rw-r--r--scene/resources/3d/separation_ray_shape_3d.h3
-rw-r--r--scene/resources/3d/shape_3d.cpp80
-rw-r--r--scene/resources/3d/shape_3d.h16
-rw-r--r--scene/resources/3d/sphere_shape_3d.cpp20
-rw-r--r--scene/resources/3d/sphere_shape_3d.h3
-rw-r--r--scene/resources/3d/world_boundary_shape_3d.cpp48
-rw-r--r--scene/resources/3d/world_boundary_shape_3d.h3
-rw-r--r--scene/resources/animation_library.cpp5
-rw-r--r--scene/resources/animation_library.h1
-rw-r--r--scene/resources/curve.cpp135
-rw-r--r--scene/resources/curve.h4
-rw-r--r--scene/resources/font.cpp8
-rw-r--r--scene/resources/mesh.cpp4
-rw-r--r--scene/resources/packed_scene.cpp14
-rw-r--r--scene/resources/resource_format_text.cpp2
-rw-r--r--scene/resources/skeleton_profile.cpp8
-rw-r--r--scene/resources/skeleton_profile.h1
-rw-r--r--scene/resources/syntax_highlighter.cpp4
-rw-r--r--scene/resources/visual_shader.cpp1
-rw-r--r--scene/resources/visual_shader_nodes.cpp27
-rw-r--r--scene/resources/visual_shader_nodes.h2
-rw-r--r--servers/rendering/dummy/storage/mesh_storage.h1
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp26
-rw-r--r--servers/rendering/renderer_rd/environment/sky.cpp122
-rw-r--r--servers/rendering/renderer_rd/environment/sky.h3
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp17
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h2
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp22
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h2
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp61
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h47
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl46
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl50
-rw-r--r--servers/rendering/renderer_rd/shaders/decal_data_inc.glsl1
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster_inc.glsl1
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/sky.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl20
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl10
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp6
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.h1
-rw-r--r--servers/rendering/renderer_scene_cull.cpp7
-rw-r--r--servers/rendering/renderer_scene_cull.h2
-rw-r--r--servers/rendering/rendering_device.cpp17
-rw-r--r--servers/rendering/rendering_device.h2
-rw-r--r--servers/rendering/rendering_device_graph.cpp43
-rw-r--r--servers/rendering/rendering_device_graph.h5
-rw-r--r--servers/rendering/rendering_server_default.h1
-rw-r--r--servers/rendering/shader_types.cpp1
-rw-r--r--servers/rendering/storage/mesh_storage.cpp4
-rw-r--r--servers/rendering/storage/mesh_storage.h2
-rw-r--r--servers/rendering_server.cpp1
-rw-r--r--servers/rendering_server.h1
-rw-r--r--tests/core/io/test_file_access.h94
-rw-r--r--tests/core/io/test_marshalls.h120
-rw-r--r--tests/core/io/test_stream_peer.h22
-rw-r--r--tests/core/math/test_projection.h (renamed from modules/text_server_fb/thorvg_bounds_iterator.cpp)75
-rw-r--r--tests/core/object/test_class_db.h23
-rw-r--r--tests/core/string/test_translation_server.h88
-rw-r--r--tests/core/variant/test_callable.h64
-rw-r--r--tests/data/floating_point_big_endian.bin1
-rw-r--r--tests/data/floating_point_little_endian.bin1
-rw-r--r--tests/data/half_precision_floating_point_big_endian.bin1
-rw-r--r--tests/data/half_precision_floating_point_little_endian.bin1
-rw-r--r--tests/scene/test_fontfile.h82
-rw-r--r--tests/scene/test_texture_progress_bar.h92
-rw-r--r--tests/test_main.cpp3
-rw-r--r--thirdparty/README.md2
-rw-r--r--thirdparty/clipper2/include/clipper2/clipper.core.h391
-rw-r--r--thirdparty/clipper2/include/clipper2/clipper.engine.h74
-rw-r--r--thirdparty/clipper2/include/clipper2/clipper.export.h123
-rw-r--r--thirdparty/clipper2/include/clipper2/clipper.h96
-rw-r--r--thirdparty/clipper2/include/clipper2/clipper.minkowski.h2
-rw-r--r--thirdparty/clipper2/include/clipper2/clipper.offset.h18
-rw-r--r--thirdparty/clipper2/include/clipper2/clipper.rectclip.h17
-rw-r--r--thirdparty/clipper2/include/clipper2/clipper.version.h2
-rw-r--r--thirdparty/clipper2/patches/clipper2-exceptions.patch8
-rw-r--r--thirdparty/clipper2/patches/gcc14-warning.patch22
-rw-r--r--thirdparty/clipper2/patches/llvm-error.patch34
-rw-r--r--thirdparty/clipper2/src/clipper.engine.cpp225
-rw-r--r--thirdparty/clipper2/src/clipper.offset.cpp364
-rw-r--r--thirdparty/clipper2/src/clipper.rectclip.cpp111
709 files changed, 16770 insertions, 8098 deletions
diff --git a/.clang-format b/.clang-format
index 338ce6b7f3..a6822dc2cd 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,6 +1,6 @@
# Commented out parameters are those with the same value as base LLVM style.
# We can uncomment them if we want to change their value, or enforce the
-# chosen value in case the base style changes (last sync: Clang 18.1.8).
+# chosen value in case the base style changes (last sync: Clang 19.1.0).
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: DontAlign
@@ -37,7 +37,29 @@ AlignAfterOpenBracket: DontAlign
# Enabled: false
# AcrossEmptyLines: false
# AcrossComments: false
+# AlignCaseArrows: false
# AlignCaseColons: false
+# AlignConsecutiveTableGenBreakingDAGArgColons:
+# Enabled: false
+# AcrossEmptyLines: false
+# AcrossComments: false
+# AlignCompound: false
+# AlignFunctionPointers: false
+# PadOperators: false
+# AlignConsecutiveTableGenCondOperatorColons:
+# Enabled: false
+# AcrossEmptyLines: false
+# AcrossComments: false
+# AlignCompound: false
+# AlignFunctionPointers: false
+# PadOperators: false
+# AlignConsecutiveTableGenDefinitionColons:
+# Enabled: false
+# AcrossEmptyLines: false
+# AcrossComments: false
+# AlignCompound: false
+# AlignFunctionPointers: false
+# PadOperators: false
# AlignEscapedNewlines: Right
AlignOperands: DontAlign
AlignTrailingComments:
@@ -47,6 +69,7 @@ AlignTrailingComments:
AllowAllParametersOfDeclarationOnNextLine: false
# AllowBreakBeforeNoexceptSpecifier: Never
# AllowShortBlocksOnASingleLine: Never
+# AllowShortCaseExpressionOnASingleLine: true
# AllowShortCaseLabelsOnASingleLine: false
# AllowShortCompoundRequirementOnASingleLine: true
# AllowShortEnumsOnASingleLine: true
@@ -54,9 +77,7 @@ AllowAllParametersOfDeclarationOnNextLine: false
# AllowShortIfStatementsOnASingleLine: Never
# AllowShortLambdasOnASingleLine: All
# AllowShortLoopsOnASingleLine: false
-# AlwaysBreakAfterReturnType: None
# AlwaysBreakBeforeMultilineStrings: false
-# AlwaysBreakTemplateDeclarations: MultiLine
# AttributeMacros:
# - __capability
# BinPackArguments: true
@@ -84,6 +105,7 @@ AllowAllParametersOfDeclarationOnNextLine: false
# BreakAdjacentStringLiterals: true
# BreakAfterAttributes: Leave
# BreakAfterJavaFieldAnnotations: false
+# BreakAfterReturnType: None
# BreakArrays: true
# BreakBeforeBinaryOperators: None
# BreakBeforeBraces: Attach
@@ -91,8 +113,10 @@ AllowAllParametersOfDeclarationOnNextLine: false
# BreakBeforeInlineASMColon: OnlyMultiline
# BreakBeforeTernaryOperators: true
BreakConstructorInitializers: AfterColon
+# BreakFunctionDefinitionParameters: false
# BreakInheritanceList: BeforeColon
# BreakStringLiterals: true
+# BreakTemplateDeclarations: MultiLine
ColumnLimit: 0
# CommentPragmas: '^ IWYU pragma:'
# CompactNamespaces: false
@@ -150,13 +174,16 @@ JavaImportGroups:
- javax
# JavaScriptQuotes: Leave
# JavaScriptWrapImports: true
-# KeepEmptyLinesAtEOF: false
-KeepEmptyLinesAtTheStartOfBlocks: false
+KeepEmptyLines:
+ AtEndOfFile: false
+ AtStartOfBlock: false
+ AtStartOfFile: false
# LambdaBodyIndentation: Signature
# Language: Cpp
# LineEnding: DeriveLF
# MacroBlockBegin: ''
# MacroBlockEnd: ''
+# MainIncludeChar: Quote
# MaxEmptyLinesToKeep: 1
# NamespaceIndentation: None
# ObjCBinPackProtocolList: Auto
@@ -219,13 +246,12 @@ RemoveSemicolon: true
# SpacesBeforeTrailingComments: 1
# SpacesInAngles: Never
# SpacesInContainerLiterals: true
-## Godot TODO: We'll want to use a min of 1, but we need to see how to fix
-## our comment capitalization at the same time.
SpacesInLineCommentPrefix:
- Minimum: 0
+ Minimum: 0 # We want a minimum of 1 for comments, but allow 0 for disabled code.
Maximum: -1
# SpacesInParens: Never
# SpacesInParensOptions:
+# ExceptDoubleParentheses: false
# InConditionalStatements: false
# InCStyleCasts: false
# InEmptyParentheses: false
@@ -238,6 +264,7 @@ Standard: c++20
# - Q_UNUSED
# - QT_REQUIRE_VERSION
TabWidth: 4
+# TableGenBreakInsideDAGArg: DontBreak
UseTab: Always
# VerilogBreakBetweenInstancePorts: true
# WhitespaceSensitiveMacros:
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 6c8a8ef919..713c982123 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -121,6 +121,7 @@
/modules/mbedtls/tests/ @godotengine/network @godotengine/tests
/modules/multiplayer/ @godotengine/network
/modules/multiplayer/doc_classes/ @godotengine/network @godotengine/documentation
+/modules/multiplayer/tests/ @godotengine/network @godotengine/tests
/modules/upnp/ @godotengine/network
/modules/upnp/doc_classes/ @godotengine/network @godotengine/documentation
/modules/webrtc/ @godotengine/network
diff --git a/.github/actions/godot-build/action.yml b/.github/actions/godot-build/action.yml
index 93d6f076b7..ebc301dd0f 100644
--- a/.github/actions/godot-build/action.yml
+++ b/.github/actions/godot-build/action.yml
@@ -18,12 +18,12 @@ inputs:
required: false
scons-cache:
description: The SCons cache path.
- default: ${{ github.workspace }}/.scons-cache/
+ default: ${{ github.workspace }}/.scons_cache/
scons-cache-limit:
description: The SCons cache size limit.
# actions/cache has 10 GiB limit, and GitHub runners have a 14 GiB disk.
# Limit to 7 GiB to avoid having the extracted cache fill the disk.
- default: 7168
+ default: 7
runs:
using: composite
@@ -32,10 +32,8 @@ runs:
shell: sh
env:
SCONSFLAGS: ${{ inputs.sconsflags }}
- SCONS_CACHE: ${{ inputs.scons-cache }}
- SCONS_CACHE_LIMIT: ${{ inputs.scons-cache-limit }}
run: |
- echo "Building with flags:" platform=${{ inputs.platform }} target=${{ inputs.target }} tests=${{ inputs.tests }} ${{ env.SCONSFLAGS }}
+ echo "Building with flags:" platform=${{ inputs.platform }} target=${{ inputs.target }} tests=${{ inputs.tests }} ${{ env.SCONSFLAGS }} "cache_path=${{ inputs.scons-cache }}" cache_limit=${{ inputs.scons-cache-limit }}
if [ "${{ inputs.target }}" != "editor" ]; then
# Ensure we don't include editor code in export template builds.
@@ -49,5 +47,5 @@ runs:
export BUILD_NAME="gh"
fi
- scons platform=${{ inputs.platform }} target=${{ inputs.target }} tests=${{ inputs.tests }} ${{ env.SCONSFLAGS }}
+ scons platform=${{ inputs.platform }} target=${{ inputs.target }} tests=${{ inputs.tests }} ${{ env.SCONSFLAGS }} "cache_path=${{ inputs.scons-cache }}" cache_limit=${{ inputs.scons-cache-limit }}
ls -l bin/
diff --git a/.github/actions/godot-cache-restore/action.yml b/.github/actions/godot-cache-restore/action.yml
index 7abec20a28..e2a1b97019 100644
--- a/.github/actions/godot-cache-restore/action.yml
+++ b/.github/actions/godot-cache-restore/action.yml
@@ -6,7 +6,7 @@ inputs:
default: ${{ github.job }}
scons-cache:
description: The SCons cache path.
- default: ${{ github.workspace }}/.scons-cache/
+ default: ${{ github.workspace }}/.scons_cache/
runs:
using: composite
@@ -29,7 +29,6 @@ runs:
# 4. A partial match for the same base branch only (not ideal, matches any PR with the same base branch).
restore-keys: |
- ${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}-${{ github.sha }}
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-${{ github.ref }}
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}-refs/heads/${{ env.GODOT_BASE_BRANCH }}
${{ inputs.cache-name }}-${{ env.GODOT_BASE_BRANCH }}
diff --git a/.github/actions/godot-cache-save/action.yml b/.github/actions/godot-cache-save/action.yml
index df877cec67..42aa836406 100644
--- a/.github/actions/godot-cache-save/action.yml
+++ b/.github/actions/godot-cache-save/action.yml
@@ -6,7 +6,7 @@ inputs:
default: ${{ github.job }}
scons-cache:
description: The SCons cache path.
- default: ${{ github.workspace }}/.scons-cache/
+ default: ${{ github.workspace }}/.scons_cache/
runs:
using: composite
diff --git a/.github/actions/godot-deps/action.yml b/.github/actions/godot-deps/action.yml
index eb9bdef1e7..3344323fd4 100644
--- a/.github/actions/godot-deps/action.yml
+++ b/.github/actions/godot-deps/action.yml
@@ -10,7 +10,7 @@ inputs:
default: x64
scons-version:
description: The SCons version to use.
- default: 4.8.0
+ default: 4.8.1
runs:
using: composite
@@ -27,6 +27,5 @@ runs:
shell: bash
run: |
python -c "import sys; print(sys.version)"
- python -m pip install wheel
python -m pip install scons==${{ inputs.scons-version }}
scons --version
diff --git a/.github/workflows/godot_cpp_test.yml b/.github/workflows/godot_cpp_test.yml
index dc82a7cb3c..af99a4b035 100644
--- a/.github/workflows/godot_cpp_test.yml
+++ b/.github/workflows/godot_cpp_test.yml
@@ -52,9 +52,6 @@ jobs:
# continue-on-error: true
- name: Build godot-cpp test extension
- env: # Keep synced with godot-build.
- SCONS_CACHE: ${{ github.workspace }}/.scons-cache/
- SCONS_CACHE_LIMIT: 7168
run: scons --directory=./godot-cpp/test target=template_debug dev_build=yes verbose=yes
# - name: Save Godot build cache
diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml
index cf653caa3d..bd4e2856e3 100644
--- a/.github/workflows/linux_builds.yml
+++ b/.github/workflows/linux_builds.yml
@@ -17,8 +17,8 @@ concurrency:
jobs:
build-linux:
- # If unspecified, stay one LTS before latest to increase portability of Linux artifacts.
- runs-on: ${{ matrix.os || 'ubuntu-22.04' }}
+ # Stay one LTS before latest to increase portability of Linux artifacts.
+ runs-on: ubuntu-22.04
name: ${{ matrix.name }}
strategy:
fail-fast: false
@@ -61,8 +61,6 @@ jobs:
artifact: false
# Test our oldest supported SCons/Python versions on one arbitrary editor build.
legacy-scons: true
- # Python 3.6 unavailable on 22.04.
- os: ubuntu-20.04
- name: Editor with ThreadSanitizer (target=editor, tests=yes, dev_build=yes, use_tsan=yes, use_llvm=yes, linker=lld)
cache-name: linux-editor-thread-sanitizer
@@ -132,8 +130,8 @@ jobs:
uses: ./.github/actions/godot-deps
with:
# Sync with Ensure*Version in SConstruct.
- python-version: 3.6
- scons-version: 3.1.2
+ python-version: 3.8
+ scons-version: 4.0
- name: Setup GCC problem matcher
uses: ammaraskar/gcc-problem-matcher@master
diff --git a/.gitignore b/.gitignore
index 32a43b8c63..f72ea1ac51 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,8 +36,8 @@ compile_commands.json
platform/windows/godot_res.res
# Ninja build files
-build.ninja
-.ninja
+*.ninja
+.ninja/
run_ninja_env.bat
# Generated by Godot binary
@@ -77,6 +77,9 @@ venv
__pycache__/
*.pyc
+# Python modules
+.*_cache/
+
# Documentation
doc/_build/
@@ -164,9 +167,6 @@ gmon.out
# Kdevelop
*.kdev4
-# Mypy
-.mypy_cache
-
# Qt Creator
*.config
*.creator
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index d81c1043a7..56f64ad079 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -50,14 +50,14 @@ repos:
stages: [manual] # Not automatically triggered, invoked via `pre-commit run --hook-stage manual clang-tidy`
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.6.6
+ rev: v0.7.3
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
- rev: v1.11.2
+ rev: v1.13.0
hooks:
- id: mypy
files: \.py$
@@ -187,7 +187,8 @@ repos:
modules/gdscript/tests/scripts/parser/warnings/empty_file_newline_comment\.notest\.gd$|
modules/gdscript/tests/scripts/parser/warnings/empty_file_newline\.notest\.gd$|
platform/android/java/editor/src/main/java/com/android/.*|
- platform/android/java/lib/src/com/google/.*
+ platform/android/java/lib/src/com/google/.*|
+ tests/data/.*\.bin$
)
- id: dotnet-format
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 2ece06eebb..46986fe1f9 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -186,7 +186,7 @@ License: MPL-2.0
Files: ./thirdparty/clipper2/
Comment: Clipper2
-Copyright: 2010-2023, Angus Johnson
+Copyright: 2010-2024, Angus Johnson
License: BSL-1.0
Files: ./thirdparty/cvtt/
diff --git a/SConstruct b/SConstruct
index ee34d421e0..fa324b2aa0 100644
--- a/SConstruct
+++ b/SConstruct
@@ -1,8 +1,8 @@
#!/usr/bin/env python
from misc.utility.scons_hints import *
-EnsureSConsVersion(3, 1, 2)
-EnsurePythonVersion(3, 6)
+EnsureSConsVersion(4, 0)
+EnsurePythonVersion(3, 8)
# System
import atexit
@@ -59,7 +59,7 @@ import glsl_builders
import methods
import scu_builders
from methods import print_error, print_warning
-from platform_methods import architecture_aliases, architectures
+from platform_methods import architecture_aliases, architectures, compatibility_platform_aliases
if ARGUMENTS.get("target", "editor") == "editor":
_helper_module("editor.editor_builders", "editor/editor_builders.py")
@@ -227,7 +227,6 @@ opts.Add(BoolVariable("use_volk", "Use the volk library to load the Vulkan loade
opts.Add(BoolVariable("disable_exceptions", "Force disabling exception handling code", True))
opts.Add("custom_modules", "A list of comma-separated directory paths containing custom modules to build.", "")
opts.Add(BoolVariable("custom_modules_recursive", "Detect custom modules recursively for each specified path.", True))
-opts.Add(BoolVariable("swappy", "Use Swappy Frame Pacing Library in Android builds.", False))
# Advanced options
opts.Add(
@@ -271,6 +270,8 @@ opts.Add(BoolVariable("scu_build", "Use single compilation unit build", False))
opts.Add("scu_limit", "Max includes per SCU file when using scu_build (determines RAM use)", "0")
opts.Add(BoolVariable("engine_update_check", "Enable engine update checks in the Project Manager", True))
opts.Add(BoolVariable("steamapi", "Enable minimal SteamAPI integration for usage time tracking (editor only)", False))
+opts.Add("cache_path", "Path to a directory where SCons cache files will be stored. No value disables the cache.", "")
+opts.Add("cache_limit", "Max size (in GiB) for the SCons cache. 0 means no limit.", "0")
# Thirdparty libraries
opts.Add(BoolVariable("builtin_brotli", "Use the built-in Brotli library", True))
@@ -321,6 +322,9 @@ opts.Add("rcflags", "Custom flags for Windows resource compiler")
# in following code (especially platform and custom_modules).
opts.Update(env)
+# Setup caching logic early to catch everything.
+methods.prepare_cache(env)
+
# Copy custom environment variables if set.
if env["import_env_vars"]:
for env_var in str(env["import_env_vars"]).split(","):
@@ -350,27 +354,18 @@ if env["platform"] == "":
if env["platform"] != "":
print(f'Automatically detected platform: {env["platform"]}')
-if env["platform"] == "osx":
- # Deprecated alias kept for compatibility.
- print_warning('Platform "osx" has been renamed to "macos" in Godot 4. Building for platform "macos".')
- env["platform"] = "macos"
-
-if env["platform"] == "iphone":
- # Deprecated alias kept for compatibility.
- print_warning('Platform "iphone" has been renamed to "ios" in Godot 4. Building for platform "ios".')
- env["platform"] = "ios"
-
-if env["platform"] in ["linux", "bsd", "x11"]:
- if env["platform"] == "x11":
- # Deprecated alias kept for compatibility.
- print_warning('Platform "x11" has been renamed to "linuxbsd" in Godot 4. Building for platform "linuxbsd".')
- # Alias for convenience.
- env["platform"] = "linuxbsd"
+# Deprecated aliases kept for compatibility.
+if env["platform"] in compatibility_platform_aliases:
+ alias = env["platform"]
+ platform = compatibility_platform_aliases[alias]
+ print_warning(
+ f'Platform "{alias}" has been renamed to "{platform}" in Godot 4. Building for platform "{platform}".'
+ )
+ env["platform"] = platform
-if env["platform"] == "javascript":
- # Deprecated alias kept for compatibility.
- print_warning('Platform "javascript" has been renamed to "web" in Godot 4. Building for platform "web".')
- env["platform"] = "web"
+# Alias for convenience.
+if env["platform"] in ["linux", "bsd"]:
+ env["platform"] = "linuxbsd"
if env["platform"] not in platform_list:
text = "The following platforms are available:\n\t{}\n".format("\n\t".join(platform_list))
@@ -387,8 +382,7 @@ if env["platform"] not in platform_list:
# Add platform-specific options.
if env["platform"] in platform_opts:
- for opt in platform_opts[env["platform"]]:
- opts.Add(opt)
+ opts.AddVariables(*platform_opts[env["platform"]])
# Platform-specific flags.
# These can sometimes override default options, so they need to be processed
@@ -444,12 +438,11 @@ for name, path in modules_detected.items():
else:
enabled = False
- opts.Add(BoolVariable("module_" + name + "_enabled", "Enable module '%s'" % (name,), enabled))
+ opts.Add(BoolVariable(f"module_{name}_enabled", f"Enable module '{name}'", enabled))
# Add module-specific options.
try:
- for opt in config.get_opts(env["platform"]):
- opts.Add(opt)
+ opts.AddVariables(*config.get_opts(env["platform"]))
except AttributeError:
pass
@@ -584,7 +577,7 @@ env.Append(RCFLAGS=env.get("rcflags", "").split())
# Feature build profile
env.disabled_classes = []
if env["build_profile"] != "":
- print('Using feature build profile: "{}"'.format(env["build_profile"]))
+ print(f'Using feature build profile: "{env["build_profile"]}"')
import json
try:
@@ -596,7 +589,7 @@ if env["build_profile"] != "":
for c in dbo:
env[c] = dbo[c]
except json.JSONDecodeError:
- print_error('Failed to open feature build profile: "{}"'.format(env["build_profile"]))
+ print_error(f'Failed to open feature build profile: "{env["build_profile"]}"')
Exit(255)
# 'dev_mode' and 'production' are aliases to set default options if they haven't been
@@ -667,40 +660,32 @@ elif methods.using_gcc(env):
"to switch to posix threads."
)
Exit(255)
- if env["debug_paths_relative"] and cc_version_major < 8:
- print_warning("GCC < 8 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option.")
- env["debug_paths_relative"] = False
elif methods.using_clang(env):
# Apple LLVM versions differ from upstream LLVM version \o/, compare
# in https://en.wikipedia.org/wiki/Xcode#Toolchain_versions
- if env["platform"] == "macos" or env["platform"] == "ios":
- vanilla = methods.is_vanilla_clang(env)
- if vanilla and cc_version_major < 6:
- print_error(
- "Detected Clang version older than 6, which does not fully support "
- "C++17. Supported versions are Clang 6 and later."
- )
- Exit(255)
- elif not vanilla and cc_version_major < 10:
+ if methods.is_apple_clang(env):
+ if cc_version_major < 10:
print_error(
"Detected Apple Clang version older than 10, which does not fully "
"support C++17. Supported versions are Apple Clang 10 and later."
)
Exit(255)
- if env["debug_paths_relative"] and not vanilla and cc_version_major < 12:
+ elif env["debug_paths_relative"] and cc_version_major < 12:
print_warning(
"Apple Clang < 12 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option."
)
env["debug_paths_relative"] = False
- elif cc_version_major < 6:
- print_error(
- "Detected Clang version older than 6, which does not fully support "
- "C++17. Supported versions are Clang 6 and later."
- )
- Exit(255)
- if env["debug_paths_relative"] and cc_version_major < 10:
- print_warning("Clang < 10 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option.")
- env["debug_paths_relative"] = False
+ else:
+ if cc_version_major < 6:
+ print_error(
+ "Detected Clang version older than 6, which does not fully support "
+ "C++17. Supported versions are Clang 6 and later."
+ )
+ Exit(255)
+ elif env["debug_paths_relative"] and cc_version_major < 10:
+ print_warning("Clang < 10 doesn't support -ffile-prefix-map, disabling `debug_paths_relative` option.")
+ env["debug_paths_relative"] = False
+
elif env.msvc:
# Ensure latest minor builds of Visual Studio 2017/2019.
# https://github.com/godotengine/godot/pull/94995#issuecomment-2336464574
@@ -764,7 +749,7 @@ else:
project_path = Dir("#").abspath
env.Append(CCFLAGS=[f"-ffile-prefix-map={project_path}=."])
else:
- if methods.using_clang(env) and not methods.is_vanilla_clang(env):
+ if methods.is_apple_clang(env):
# Apple Clang, its linker doesn't like -s.
env.Append(LINKFLAGS=["-Wl,-S", "-Wl,-x", "-Wl,-dead_strip"])
else:
@@ -866,8 +851,6 @@ else: # GCC, Clang
if methods.using_gcc(env):
common_warnings += ["-Wshadow", "-Wno-misleading-indentation"]
- if cc_version_major == 7: # Bogus warning fixed in 8+.
- common_warnings += ["-Wno-strict-overflow"]
if cc_version_major < 11:
# Regression in GCC 9/10, spams so much in our variadic templates
# that we need to outright disable it.
@@ -943,7 +926,7 @@ env.module_icons_paths = []
env.doc_class_path = platform_doc_class_path
for name, path in modules_detected.items():
- if not env["module_" + name + "_enabled"]:
+ if not env[f"module_{name}_enabled"]:
continue
sys.path.insert(0, path)
env.current_module = name
@@ -1050,35 +1033,19 @@ GLSL_BUILDERS = {
}
env.Append(BUILDERS=GLSL_BUILDERS)
-scons_cache_path = os.environ.get("SCONS_CACHE")
-if scons_cache_path is not None:
- CacheDir(scons_cache_path)
- print("Scons cache enabled... (path: '" + scons_cache_path + "')")
-
-if env["vsproj"]:
- env.vs_incs = []
- env.vs_srcs = []
-
if env["compiledb"]:
- if env.scons_version < (4, 0, 0):
- # Generating the compilation DB (`compile_commands.json`) requires SCons 4.0.0 or later.
- print_error(
- "The `compiledb=yes` option requires SCons 4.0 or later, but your version is %s." % scons_raw_version
- )
- Exit(255)
-
env.Tool("compilation_db")
env.Alias("compiledb", env.CompilationDatabase())
if env["ninja"]:
if env.scons_version < (4, 2, 0):
- print_error("The `ninja=yes` option requires SCons 4.2 or later, but your version is %s." % scons_raw_version)
+ print_error(f"The `ninja=yes` option requires SCons 4.2 or later, but your version is {scons_raw_version}.")
Exit(255)
SetOption("experimental", "ninja")
env["NINJA_FILE_NAME"] = env["ninja_file"]
env["NINJA_DISABLE_AUTO_RUN"] = not env["ninja_auto_run"]
- env.Tool("ninja", "build.ninja")
+ env.Tool("ninja", env["ninja_file"])
# Threads
if env["threads"]:
@@ -1140,7 +1107,7 @@ atexit.register(print_elapsed_time)
def purge_flaky_files():
- paths_to_keep = ["build.ninja"]
+ paths_to_keep = [env["ninja_file"]]
for build_failure in GetBuildFailures():
path = build_failure.node.path
if os.path.isfile(path) and path not in paths_to_keep:
@@ -1148,5 +1115,3 @@ def purge_flaky_files():
atexit.register(purge_flaky_files)
-
-methods.clean_cache(env)
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 092177bc15..6c28b00f48 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -194,7 +194,7 @@ String ProjectSettings::localize_path(const String &p_path) const {
return cwd.replace_first(res_path, "res://");
} else {
- int sep = path.rfind("/");
+ int sep = path.rfind_char('/');
if (sep == -1) {
return "res://" + path;
}
@@ -262,6 +262,12 @@ String ProjectSettings::globalize_path(const String &p_path) const {
return p_path.replace("res:/", resource_path);
}
return p_path.replace("res://", "");
+ } else if (p_path.begins_with("uid://")) {
+ const String path = ResourceUID::uid_to_path(p_path);
+ if (!resource_path.is_empty()) {
+ return path.replace("res:/", resource_path);
+ }
+ return path.replace("res://", "");
} else if (p_path.begins_with("user://")) {
String data_dir = OS::get_singleton()->get_user_data_dir();
if (!data_dir.is_empty()) {
@@ -300,7 +306,7 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) {
}
{ // Feature overrides.
- int dot = p_name.operator String().find(".");
+ int dot = p_name.operator String().find_char('.');
if (dot != -1) {
Vector<String> s = p_name.operator String().split(".");
@@ -435,7 +441,7 @@ void ProjectSettings::_get_property_list(List<PropertyInfo> *p_list) const {
for (const _VCSort &E : vclist) {
String prop_info_name = E.name;
- int dot = prop_info_name.find(".");
+ int dot = prop_info_name.find_char('.');
if (dot != -1 && !custom_prop_info.has(prop_info_name)) {
prop_info_name = prop_info_name.substr(0, dot);
}
@@ -508,16 +514,19 @@ void ProjectSettings::_convert_to_last_version(int p_from_version) {
}
}
}
- if (p_from_version <= 5) {
- // Converts the device in events from -1 (emulated events) to -3 (all events).
+ if (p_from_version == 5) {
+ // Converts the device in events from -3 to -1.
+ // -3 was introduced in GH-97707 as a way to prevent a clash in device IDs, but as reported in GH-99243, this leads to problems.
+ // -3 was used during dev-releases, so this conversion helps to revert such affected projects.
+ // This conversion doesn't affect any other projects, since -3 is not used otherwise.
for (KeyValue<StringName, ProjectSettings::VariantContainer> &E : props) {
if (String(E.key).begins_with("input/")) {
Dictionary action = E.value.variant;
Array events = action["events"];
for (int i = 0; i < events.size(); i++) {
Ref<InputEvent> ev = events[i];
- if (ev.is_valid() && ev->get_device() == -1) { // -1 was the previous value (GH-97707).
- ev->set_device(InputEvent::DEVICE_ID_ALL_DEVICES);
+ if (ev.is_valid() && ev->get_device() == -3) {
+ ev->set_device(-1);
}
}
}
@@ -1092,7 +1101,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
String category = E.name;
String name = E.name;
- int div = category.find("/");
+ int div = category.find_char('/');
if (div < 0) {
category = "";
@@ -1408,7 +1417,7 @@ void ProjectSettings::_add_builtin_input_map() {
}
Dictionary action;
- action["deadzone"] = Variant(0.2f);
+ action["deadzone"] = Variant(InputMap::DEFAULT_DEADZONE);
action["events"] = events;
String action_name = "input/" + E.key;
diff --git a/core/core_bind.compat.inc b/core/core_bind.compat.inc
index 3e8ac3c5de..22c78623da 100644
--- a/core/core_bind.compat.inc
+++ b/core/core_bind.compat.inc
@@ -44,11 +44,16 @@ void Semaphore::_bind_compatibility_methods() {
// OS
+String OS::_read_string_from_stdin_bind_compat_91201() {
+ return read_string_from_stdin(1024);
+}
+
Dictionary OS::_execute_with_pipe_bind_compat_94434(const String &p_path, const Vector<String> &p_arguments) {
return execute_with_pipe(p_path, p_arguments, true);
}
void OS::_bind_compatibility_methods() {
+ ClassDB::bind_compatibility_method(D_METHOD("read_string_from_stdin"), &OS::_read_string_from_stdin_bind_compat_91201);
ClassDB::bind_compatibility_method(D_METHOD("execute_with_pipe", "path", "arguments"), &OS::_execute_with_pipe_bind_compat_94434);
}
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 967a7fba75..925551d933 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -308,8 +308,24 @@ Error OS::shell_show_in_file_manager(const String &p_path, bool p_open_folder) {
return ::OS::get_singleton()->shell_show_in_file_manager(p_path, p_open_folder);
}
-String OS::read_string_from_stdin() {
- return ::OS::get_singleton()->get_stdin_string();
+String OS::read_string_from_stdin(int64_t p_buffer_size) {
+ return ::OS::get_singleton()->get_stdin_string(p_buffer_size);
+}
+
+PackedByteArray OS::read_buffer_from_stdin(int64_t p_buffer_size) {
+ return ::OS::get_singleton()->get_stdin_buffer(p_buffer_size);
+}
+
+OS::StdHandleType OS::get_stdin_type() const {
+ return (OS::StdHandleType)::OS::get_singleton()->get_stdin_type();
+}
+
+OS::StdHandleType OS::get_stdout_type() const {
+ return (OS::StdHandleType)::OS::get_singleton()->get_stdout_type();
+}
+
+OS::StdHandleType OS::get_stderr_type() const {
+ return (OS::StdHandleType)::OS::get_singleton()->get_stderr_type();
}
int OS::execute(const String &p_path, const Vector<String> &p_arguments, Array r_output, bool p_read_stderr, bool p_open_console) {
@@ -633,7 +649,13 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_system_font_path", "font_name", "weight", "stretch", "italic"), &OS::get_system_font_path, DEFVAL(400), DEFVAL(100), DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_system_font_path_for_text", "font_name", "text", "locale", "script", "weight", "stretch", "italic"), &OS::get_system_font_path_for_text, DEFVAL(String()), DEFVAL(String()), DEFVAL(400), DEFVAL(100), DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_executable_path"), &OS::get_executable_path);
- ClassDB::bind_method(D_METHOD("read_string_from_stdin"), &OS::read_string_from_stdin);
+
+ ClassDB::bind_method(D_METHOD("read_string_from_stdin", "buffer_size"), &OS::read_string_from_stdin);
+ ClassDB::bind_method(D_METHOD("read_buffer_from_stdin", "buffer_size"), &OS::read_buffer_from_stdin);
+ ClassDB::bind_method(D_METHOD("get_stdin_type"), &OS::get_stdin_type);
+ ClassDB::bind_method(D_METHOD("get_stdout_type"), &OS::get_stdout_type);
+ ClassDB::bind_method(D_METHOD("get_stderr_type"), &OS::get_stderr_type);
+
ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "output", "read_stderr", "open_console"), &OS::execute, DEFVAL_ARRAY, DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("execute_with_pipe", "path", "arguments", "blocking"), &OS::execute_with_pipe, DEFVAL(true));
ClassDB::bind_method(D_METHOD("create_process", "path", "arguments", "open_console"), &OS::create_process, DEFVAL(false));
@@ -725,6 +747,12 @@ void OS::_bind_methods() {
BIND_ENUM_CONSTANT(SYSTEM_DIR_MUSIC);
BIND_ENUM_CONSTANT(SYSTEM_DIR_PICTURES);
BIND_ENUM_CONSTANT(SYSTEM_DIR_RINGTONES);
+
+ BIND_ENUM_CONSTANT(STD_HANDLE_INVALID);
+ BIND_ENUM_CONSTANT(STD_HANDLE_CONSOLE);
+ BIND_ENUM_CONSTANT(STD_HANDLE_FILE);
+ BIND_ENUM_CONSTANT(STD_HANDLE_PIPE);
+ BIND_ENUM_CONSTANT(STD_HANDLE_UNKNOWN);
}
////// Geometry2D //////
diff --git a/core/core_bind.h b/core/core_bind.h
index 3ae54017fe..d013e348bd 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -134,6 +134,7 @@ protected:
#ifndef DISABLE_DEPRECATED
Dictionary _execute_with_pipe_bind_compat_94434(const String &p_path, const Vector<String> &p_arguments);
+ String _read_string_from_stdin_bind_compat_91201();
static void _bind_compatibility_methods();
#endif
@@ -148,6 +149,14 @@ public:
PackedByteArray get_entropy(int p_bytes);
String get_system_ca_certificates();
+ enum StdHandleType {
+ STD_HANDLE_INVALID,
+ STD_HANDLE_CONSOLE,
+ STD_HANDLE_FILE,
+ STD_HANDLE_PIPE,
+ STD_HANDLE_UNKNOWN,
+ };
+
virtual PackedStringArray get_connected_midi_inputs();
virtual void open_midi_inputs();
virtual void close_midi_inputs();
@@ -168,7 +177,13 @@ public:
String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const;
Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const;
String get_executable_path() const;
- String read_string_from_stdin();
+
+ String read_string_from_stdin(int64_t p_buffer_size = 1024);
+ PackedByteArray read_buffer_from_stdin(int64_t p_buffer_size = 1024);
+ StdHandleType get_stdin_type() const;
+ StdHandleType get_stdout_type() const;
+ StdHandleType get_stderr_type() const;
+
int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = ClassDB::default_array_arg, bool p_read_stderr = false, bool p_open_console = false);
Dictionary execute_with_pipe(const String &p_path, const Vector<String> &p_arguments, bool p_blocking = true);
int create_process(const String &p_path, const Vector<String> &p_arguments, bool p_open_console = false);
@@ -644,6 +659,7 @@ VARIANT_BITFIELD_CAST(core_bind::ResourceSaver::SaverFlags);
VARIANT_ENUM_CAST(core_bind::OS::RenderingDriver);
VARIANT_ENUM_CAST(core_bind::OS::SystemDir);
+VARIANT_ENUM_CAST(core_bind::OS::StdHandleType);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyBooleanOperation);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType);
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index 25da49fa5c..cdb4f2c800 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -678,6 +678,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_HIDE_QUATERNION_EDIT);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PASSWORD);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_TOOL_BUTTON);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ONESHOT);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX);
BIND_CORE_BITFIELD_FLAG(PROPERTY_USAGE_NONE);
diff --git a/core/debugger/engine_debugger.cpp b/core/debugger/engine_debugger.cpp
index 6d2868cef2..a9f87ad825 100644
--- a/core/debugger/engine_debugger.cpp
+++ b/core/debugger/engine_debugger.cpp
@@ -163,7 +163,7 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, co
for (int i = 0; i < p_breakpoints.size(); i++) {
const String &bp = p_breakpoints[i];
- int sp = bp.rfind(":");
+ int sp = bp.rfind_char(':');
ERR_CONTINUE_MSG(sp == -1, vformat("Invalid breakpoint: '%s', expected file:line format.", bp));
singleton_script_debugger->insert_breakpoint(bp.substr(sp + 1, bp.length()).to_int(), bp.substr(0, sp));
diff --git a/core/debugger/local_debugger.cpp b/core/debugger/local_debugger.cpp
index dc46ffc307..a5d807f66b 100644
--- a/core/debugger/local_debugger.cpp
+++ b/core/debugger/local_debugger.cpp
@@ -171,7 +171,7 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
} else {
String key_value = line.get_slicec(' ', 1);
- int value_pos = key_value.find("=");
+ int value_pos = key_value.find_char('=');
if (value_pos < 0) {
print_line("Error: Invalid set format. Use: set key=value");
@@ -208,10 +208,10 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
print_variables(members, values, variable_prefix);
} else if (line.begins_with("p") || line.begins_with("print")) {
- if (line.get_slice_count(" ") <= 1) {
- print_line("Usage: print <expre>");
+ if (line.find_char(' ') < 0) {
+ print_line("Usage: print <expression>");
} else {
- String expr = line.get_slicec(' ', 2);
+ String expr = line.split(" ", true, 1)[1];
String res = script_lang->debug_parse_stack_level_expression(current_frame, expr);
print_line(res);
}
@@ -344,7 +344,7 @@ Pair<String, int> LocalDebugger::to_breakpoint(const String &p_line) {
String breakpoint_part = p_line.get_slicec(' ', 1);
Pair<String, int> breakpoint;
- int last_colon = breakpoint_part.rfind(":");
+ int last_colon = breakpoint_part.rfind_char(':');
if (last_colon < 0) {
print_line("Error: Invalid breakpoint format. Expected [source:line]");
return breakpoint;
diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp
index a02354b377..f8e42e6d92 100644
--- a/core/debugger/remote_debugger.cpp
+++ b/core/debugger/remote_debugger.cpp
@@ -338,7 +338,7 @@ void RemoteDebugger::_send_stack_vars(List<String> &p_names, List<Variant> &p_va
}
Error RemoteDebugger::_try_capture(const String &p_msg, const Array &p_data, bool &r_captured) {
- const int idx = p_msg.find(":");
+ const int idx = p_msg.find_char(':');
r_captured = false;
if (idx < 0) { // No prefix, unknown message.
return OK;
@@ -610,7 +610,7 @@ void RemoteDebugger::poll_events(bool p_is_idle) {
ERR_CONTINUE(arr[1].get_type() != Variant::ARRAY);
const String cmd = arr[0];
- const int idx = cmd.find(":");
+ const int idx = cmd.find_char(':');
bool parsed = false;
if (idx < 0) { // Not prefix, use scripts capture.
capture_parse("core", cmd, arr[1], parsed);
diff --git a/core/debugger/remote_debugger_peer.cpp b/core/debugger/remote_debugger_peer.cpp
index 793db7330f..d38fbc8d91 100644
--- a/core/debugger/remote_debugger_peer.cpp
+++ b/core/debugger/remote_debugger_peer.cpp
@@ -224,7 +224,7 @@ RemoteDebuggerPeer *RemoteDebuggerPeerTCP::create(const String &p_uri) {
uint16_t debug_port = 6007;
if (debug_host.contains(":")) {
- int sep_pos = debug_host.rfind(":");
+ int sep_pos = debug_host.rfind_char(':');
debug_port = debug_host.substr(sep_pos + 1).to_int();
debug_host = debug_host.substr(0, sep_pos);
}
diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp
index 05ba114a96..258b01542e 100644
--- a/core/extension/gdextension.cpp
+++ b/core/extension/gdextension.cpp
@@ -154,7 +154,7 @@ public:
}
virtual bool is_vararg() const override {
- return false;
+ return vararg;
}
#ifdef TOOLS_ENABLED
diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp
index 203f7960dc..85d53c31ec 100644
--- a/core/extension/gdextension_interface.cpp
+++ b/core/extension/gdextension_interface.cpp
@@ -700,6 +700,91 @@ static GDExtensionTypeFromVariantConstructorFunc gdextension_get_variant_to_type
ERR_FAIL_V_MSG(nullptr, "Getting Variant conversion function with invalid type");
}
+static GDExtensionVariantGetInternalPtrFunc gdextension_variant_get_ptr_internal_getter(GDExtensionVariantType p_type) {
+ switch (p_type) {
+ case GDEXTENSION_VARIANT_TYPE_BOOL:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<bool *(*)(Variant *)>(VariantInternal::get_bool));
+ case GDEXTENSION_VARIANT_TYPE_INT:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<int64_t *(*)(Variant *)>(VariantInternal::get_int));
+ case GDEXTENSION_VARIANT_TYPE_FLOAT:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<double *(*)(Variant *)>(VariantInternal::get_float));
+ case GDEXTENSION_VARIANT_TYPE_STRING:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<String *(*)(Variant *)>(VariantInternal::get_string));
+ case GDEXTENSION_VARIANT_TYPE_VECTOR2:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Vector2 *(*)(Variant *)>(VariantInternal::get_vector2));
+ case GDEXTENSION_VARIANT_TYPE_VECTOR2I:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Vector2i *(*)(Variant *)>(VariantInternal::get_vector2i));
+ case GDEXTENSION_VARIANT_TYPE_RECT2:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Rect2 *(*)(Variant *)>(VariantInternal::get_rect2));
+ case GDEXTENSION_VARIANT_TYPE_RECT2I:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Rect2i *(*)(Variant *)>(VariantInternal::get_rect2i));
+ case GDEXTENSION_VARIANT_TYPE_VECTOR3:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Vector3 *(*)(Variant *)>(VariantInternal::get_vector3));
+ case GDEXTENSION_VARIANT_TYPE_VECTOR3I:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Vector3i *(*)(Variant *)>(VariantInternal::get_vector3i));
+ case GDEXTENSION_VARIANT_TYPE_TRANSFORM2D:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Transform2D *(*)(Variant *)>(VariantInternal::get_transform2d));
+ case GDEXTENSION_VARIANT_TYPE_VECTOR4:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Vector4 *(*)(Variant *)>(VariantInternal::get_vector4));
+ case GDEXTENSION_VARIANT_TYPE_VECTOR4I:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Vector4i *(*)(Variant *)>(VariantInternal::get_vector4i));
+ case GDEXTENSION_VARIANT_TYPE_PLANE:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Plane *(*)(Variant *)>(VariantInternal::get_plane));
+ case GDEXTENSION_VARIANT_TYPE_QUATERNION:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Quaternion *(*)(Variant *)>(VariantInternal::get_quaternion));
+ case GDEXTENSION_VARIANT_TYPE_AABB:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<AABB *(*)(Variant *)>(VariantInternal::get_aabb));
+ case GDEXTENSION_VARIANT_TYPE_BASIS:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Basis *(*)(Variant *)>(VariantInternal::get_basis));
+ case GDEXTENSION_VARIANT_TYPE_TRANSFORM3D:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Transform3D *(*)(Variant *)>(VariantInternal::get_transform));
+ case GDEXTENSION_VARIANT_TYPE_PROJECTION:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Projection *(*)(Variant *)>(VariantInternal::get_projection));
+ case GDEXTENSION_VARIANT_TYPE_COLOR:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Color *(*)(Variant *)>(VariantInternal::get_color));
+ case GDEXTENSION_VARIANT_TYPE_STRING_NAME:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<StringName *(*)(Variant *)>(VariantInternal::get_string_name));
+ case GDEXTENSION_VARIANT_TYPE_NODE_PATH:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<NodePath *(*)(Variant *)>(VariantInternal::get_node_path));
+ case GDEXTENSION_VARIANT_TYPE_RID:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<RID *(*)(Variant *)>(VariantInternal::get_rid));
+ case GDEXTENSION_VARIANT_TYPE_OBJECT:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Object **(*)(Variant *)>(VariantInternal::get_object));
+ case GDEXTENSION_VARIANT_TYPE_CALLABLE:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Callable *(*)(Variant *)>(VariantInternal::get_callable));
+ case GDEXTENSION_VARIANT_TYPE_SIGNAL:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Signal *(*)(Variant *)>(VariantInternal::get_signal));
+ case GDEXTENSION_VARIANT_TYPE_DICTIONARY:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Dictionary *(*)(Variant *)>(VariantInternal::get_dictionary));
+ case GDEXTENSION_VARIANT_TYPE_ARRAY:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<Array *(*)(Variant *)>(VariantInternal::get_array));
+ case GDEXTENSION_VARIANT_TYPE_PACKED_BYTE_ARRAY:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedByteArray *(*)(Variant *)>(VariantInternal::get_byte_array));
+ case GDEXTENSION_VARIANT_TYPE_PACKED_INT32_ARRAY:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedInt32Array *(*)(Variant *)>(VariantInternal::get_int32_array));
+ case GDEXTENSION_VARIANT_TYPE_PACKED_INT64_ARRAY:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedInt64Array *(*)(Variant *)>(VariantInternal::get_int64_array));
+ case GDEXTENSION_VARIANT_TYPE_PACKED_FLOAT32_ARRAY:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedFloat32Array *(*)(Variant *)>(VariantInternal::get_float32_array));
+ case GDEXTENSION_VARIANT_TYPE_PACKED_FLOAT64_ARRAY:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedFloat64Array *(*)(Variant *)>(VariantInternal::get_float64_array));
+ case GDEXTENSION_VARIANT_TYPE_PACKED_STRING_ARRAY:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedStringArray *(*)(Variant *)>(VariantInternal::get_string_array));
+ case GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR2_ARRAY:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedVector2Array *(*)(Variant *)>(VariantInternal::get_vector2_array));
+ case GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR3_ARRAY:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedVector3Array *(*)(Variant *)>(VariantInternal::get_vector3_array));
+ case GDEXTENSION_VARIANT_TYPE_PACKED_COLOR_ARRAY:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedColorArray *(*)(Variant *)>(VariantInternal::get_color_array));
+ case GDEXTENSION_VARIANT_TYPE_PACKED_VECTOR4_ARRAY:
+ return reinterpret_cast<GDExtensionVariantGetInternalPtrFunc>(static_cast<PackedVector4Array *(*)(Variant *)>(VariantInternal::get_vector4_array));
+ case GDEXTENSION_VARIANT_TYPE_NIL:
+ case GDEXTENSION_VARIANT_TYPE_VARIANT_MAX:
+ ERR_FAIL_V_MSG(nullptr, "Getting Variant get internal pointer function with invalid type.");
+ }
+ ERR_FAIL_V_MSG(nullptr, "Getting Variant get internal pointer function with invalid type.");
+}
+
// ptrcalls
static GDExtensionPtrOperatorEvaluator gdextension_variant_get_ptr_operator_evaluator(GDExtensionVariantOperator p_operator, GDExtensionVariantType p_type_a, GDExtensionVariantType p_type_b) {
return (GDExtensionPtrOperatorEvaluator)Variant::get_ptr_operator_evaluator(Variant::Operator(p_operator), Variant::Type(p_type_a), Variant::Type(p_type_b));
@@ -1625,6 +1710,7 @@ void gdextension_setup_interface() {
REGISTER_INTERFACE_FUNC(variant_can_convert_strict);
REGISTER_INTERFACE_FUNC(get_variant_from_type_constructor);
REGISTER_INTERFACE_FUNC(get_variant_to_type_constructor);
+ REGISTER_INTERFACE_FUNC(variant_get_ptr_internal_getter);
REGISTER_INTERFACE_FUNC(variant_get_ptr_operator_evaluator);
REGISTER_INTERFACE_FUNC(variant_get_ptr_builtin_method);
REGISTER_INTERFACE_FUNC(variant_get_ptr_constructor);
diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h
index 374dbfd071..8268afc3ad 100644
--- a/core/extension/gdextension_interface.h
+++ b/core/extension/gdextension_interface.h
@@ -198,6 +198,7 @@ typedef struct {
typedef void (*GDExtensionVariantFromTypeConstructorFunc)(GDExtensionUninitializedVariantPtr, GDExtensionTypePtr);
typedef void (*GDExtensionTypeFromVariantConstructorFunc)(GDExtensionUninitializedTypePtr, GDExtensionVariantPtr);
+typedef void *(*GDExtensionVariantGetInternalPtrFunc)(GDExtensionVariantPtr);
typedef void (*GDExtensionPtrOperatorEvaluator)(GDExtensionConstTypePtr p_left, GDExtensionConstTypePtr p_right, GDExtensionTypePtr r_result);
typedef void (*GDExtensionPtrBuiltInMethod)(GDExtensionTypePtr p_base, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return, int p_argument_count);
typedef void (*GDExtensionPtrConstructor)(GDExtensionUninitializedTypePtr p_base, const GDExtensionConstTypePtr *p_args);
@@ -1384,6 +1385,23 @@ typedef GDExtensionVariantFromTypeConstructorFunc (*GDExtensionInterfaceGetVaria
typedef GDExtensionTypeFromVariantConstructorFunc (*GDExtensionInterfaceGetVariantToTypeConstructor)(GDExtensionVariantType p_type);
/**
+ * @name variant_get_ptr_internal_getter
+ * @since 4.4
+ *
+ * Provides a function pointer for retrieving a pointer to a variant's internal value.
+ * Access to a variant's internal value can be used to modify it in-place, or to retrieve its value without the overhead of variant conversion functions.
+ * It is recommended to cache the getter for all variant types in a function table to avoid retrieval overhead upon use.
+ *
+ * @note Each function assumes the variant's type has already been determined and matches the function.
+ * Invoking the function with a variant of a mismatched type has undefined behavior, and may lead to a segmentation fault.
+ *
+ * @param p_type The Variant type.
+ *
+ * @return A pointer to a type-specific function that returns a pointer to the internal value of a variant. Check the implementation of this function (gdextension_variant_get_ptr_internal_getter) for pointee type info of each variant type.
+ */
+typedef GDExtensionVariantGetInternalPtrFunc (*GDExtensionInterfaceGetVariantGetInternalPtrFunc)(GDExtensionVariantType p_type);
+
+/**
* @name variant_get_ptr_operator_evaluator
* @since 4.1
*
diff --git a/core/input/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt
index 7150911e75..50a7db5efd 100644
--- a/core/input/gamecontrollerdb.txt
+++ b/core/input/gamecontrollerdb.txt
@@ -3,6 +3,7 @@
# Windows
03000000300f00000a01000000000000,3 In 1 Conversion Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows,
+03000000fa190000918d000000000000,3 In 1 Conversion Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows,
03000000fa2d00000100000000000000,3dRudder Foot Motion Controller,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows,
03000000d0160000040d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows,
03000000d0160000050d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows,
@@ -19,6 +20,7 @@
03000000801000000900000000000000,8BitDo F30 Arcade Stick,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+05000000c82d00006a28000000000000,8BitDo GameCube,a:b0,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b9,paddle2:b8,rightshoulder:b10,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b1,y:b4,platform:Windows,
03000000c82d00001251000000000000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00001151000000000000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000150000000000000,8BitDo M30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
@@ -72,6 +74,8 @@
03000000c82d00000260000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000261000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00001230000000000000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00001b30000000000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00001d30000000000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001530000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001630000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001730000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
@@ -108,13 +112,14 @@
03000000830500000160000000000000,Arcade,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b4,platform:Windows,
03000000120c0000100e000000000000,Armor 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000490b00004406000000000000,ASCII Seamic Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
-03000000869800002500000000000000,Astro C40 TR PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000869800002500000000000000,Astro C40 TR PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000a30c00002700000000000000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000a30c00002800000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000050b00000579000000000000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000050b00000679000000000000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000503200000110000000000000,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,start:b3,platform:Windows,
03000000503200000210000000000000,Atari VCS Modern Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,
+03000000380800001889000000000000,AtGames Legends Gamer Pro,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b14,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000008a3500000102000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,platform:Windows,
030000008a3500000201000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,platform:Windows,
030000008a3500000302000000000000,Backbone One,a:b4,b:b5,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b10,leftstick:b17,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b18,righttrigger:b13,rightx:a3,righty:a4,start:b15,x:b7,y:b8,platform:Windows,
@@ -124,7 +129,7 @@
03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows,
030000006f0e00003201000000000000,Battlefield 4 PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000ad1b000001f9000000000000,BB 070,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
-03000000d62000002a79000000000000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000d62000002a79000000000000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000bc2000005250000000000000,Beitong G3,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a3,righty:a4,start:b15,x:b3,y:b4,platform:Windows,
030000000d0500000208000000000000,Belkin Nostromo N40,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
03000000bc2000006012000000000000,Betop 2126F,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
@@ -141,8 +146,8 @@
030000006b1400000209000000000000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006b1400000055000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
030000006b1400000103000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
-03000000120c0000200e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
-03000000120c0000210e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000200e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+03000000120c0000210e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000120c0000f10e000000000000,Brook PS2 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000310c000000000000,Brook Super Converter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000d81d00000b00000000000000,Buffalo BSGP1601 Series,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows,
@@ -224,7 +229,7 @@
030000004c0e00001035000000000000,Gamester,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
030000000d0f00001110000000000000,GameStick Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
0300000047530000616d000000000000,GameStop,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
-03000000c01100000140000000000000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000c01100000140000000000000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000b62500000100000000000000,Gametel GT004 01,a:b3,b:b0,dpdown:b10,dpleft:b9,dpright:b8,dpup:b11,leftshoulder:b4,rightshoulder:b5,start:b7,x:b1,y:b2,platform:Windows,
030000008f0e00001411000000000000,Gamo2 Divaller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000a857000000000000,Gator Claw,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
@@ -258,7 +263,7 @@
030000000d0f00002500000000000000,Hori Fighting Commander 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00002d00000000000000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00005f00000000000000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
-030000000d0f00005e00000000000000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00005e00000000000000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
030000000d0f00008400000000000000,Hori Fighting Commander 5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00006201000000000000,Hori Fighting Commander Octa,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00006401000000000000,Hori Fighting Commander Octa,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,start:b7,x:b2,y:b3,platform:Windows,
@@ -266,7 +271,7 @@
030000000d0f00008600000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f0000ba00000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f00008800000000000000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,
-030000000d0f00008700000000000000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00008700000000000000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
030000000d0f00001000000000000000,Hori Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00003200000000000000,Hori Fightstick 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f0000c000000000000000,Hori Fightstick 4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
@@ -276,8 +281,8 @@
030000000d0f00002100000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00002700000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f0000a000000000000000,Hori Grip TAC4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b13,x:b0,y:b3,platform:Windows,
-030000000d0f0000a500000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-030000000d0f0000a600000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f0000a500000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+030000000d0f0000a600000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
030000000d0f00000101000000000000,Hori Mini Hatsune Miku FT,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00005400000000000000,Hori Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00000900000000000000,Hori Pad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
@@ -311,18 +316,20 @@
030000000d0f00001300000000000000,Horipad 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00005500000000000000,Horipad 4 FPS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00006e00000000000000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
-030000000d0f00006600000000000000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000000d0f00006600000000000000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
030000000d0f00004200000000000000,Horipad A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000ad1b000001f5000000000000,Horipad EXT2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f0000ee00000000000000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f0000c100000000000000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f0000f600000000000000,Horipad Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
030000000d0f00006700000000000000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000000d0f00009601000000000000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b2,paddle1:b15,paddle2:b5,paddle3:b19,paddle4:b18,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
030000000d0f0000dc00000000000000,Horipad Switch,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000242e00000b20000000000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Windows,
03000000242e0000ff0b000000000000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Windows,
03000000790000004e95000000000000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Windows,
03000000242e00006a48000000000000,Hyperkin RetroN Sq,a:b3,b:b7,back:b5,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b0,rightshoulder:b1,start:b4,x:b2,y:b6,platform:Windows,
+03000000242f00000a20000000000000,Hyperkin Scout,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,
03000000242e00006a38000000000000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,platform:Windows,
03000000d81d00000e00000000000000,iBuffalo AC02 Arcade Joystick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,rightx:a2,righty:a5,start:b8,x:b4,y:b5,platform:Windows,
03000000d81d00000f00000000000000,iBuffalo BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
@@ -377,22 +384,22 @@
03000000380700006352000000000000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000380700006652000000000000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
03000000380700005032000000000000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
-03000000380700005082000000000000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700005082000000000000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000380700008031000000000000,Mad Catz FightStick Alpha PS3 ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000003807000038b7000000000000,Mad Catz Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
03000000380700008433000000000000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
-03000000380700008483000000000000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700008483000000000000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000380700008134000000000000,Mad Catz Fightstick TE2 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
-03000000380700008184000000000000,Mad Catz Fightstick TE2 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700008184000000000000,Mad Catz Fightstick TE2 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000380700006252000000000000,Mad Catz Micro CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
03000000380700008232000000000000,Mad Catz PlayStation Brawlpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000380700008731000000000000,Mad Catz PlayStation Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000003807000056a8000000000000,Mad Catz PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000380700001888000000000000,Mad Catz SFIV Fightstick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
-03000000380700008081000000000000,Mad Catz SFV Arcade Fightstick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700008081000000000000,Mad Catz SFV Arcade Fightstick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000380700001847000000000000,Mad Catz Street Fighter 4 Xbox 360 FightStick,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
03000000380700008034000000000000,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
-03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
030000002a0600001024000000000000,Matricom,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,
030000009f000000adbb000000000000,MaxJoypad Virtual Controller,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,platform:Windows,
@@ -405,6 +412,7 @@
03000000242f00007300000000000000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,
0300000079000000d218000000000000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000d620000010a7000000000000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000242e0000f500000000000000,Mayflash N64 Adapter,a:b2,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a5,start:b9,platform:Windows,
03000000242f0000f400000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a5,start:b9,platform:Windows,
03000000790000007918000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,righttrigger:b7,rightx:a3,righty:a2,start:b8,platform:Windows,
030000008f0e00001030000000000000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
@@ -436,11 +444,12 @@
03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
03000000091200004488000000000000,MUSIA PlayStation 2 Input Display,a:b0,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:b11,rightx:a2,righty:a3,start:b5,x:b1,y:b3,platform:Windows,
03000000f70600000100000000000000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Windows,
+030000006f0e00001311000000000000,N64 Controller,+rightx:b10,+righty:b3,-rightx:b0,-righty:b11,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,platform:Windows,
030000006b140000010c000000000000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
-030000006b1400001106000000000000,Nacon Revolution 3 PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000006b1400001106000000000000,Nacon Revolution 3 PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
0300000085320000170d000000000000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
0300000085320000190d000000000000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
-030000006b140000100d000000000000,Nacon Revolution Infinity PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006b140000100d000000000000,Nacon Revolution Infinity PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
030000006b140000080d000000000000,Nacon Revolution Unlimited Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000bd12000001c0000000000000,Nebular,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
03000000eb0300000000000000000000,NeGcon Adapter,a:a2,b:b13,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,lefttrigger:a4,leftx:a1,righttrigger:b11,start:b3,x:a3,y:b12,platform:Windows,
@@ -475,6 +484,7 @@
03000000790000002201000000000000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
030000006f0e00008501000000000000,PDP Fightpad Pro GameCube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
030000006f0e00000901000000000000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00008901000000000000,PDP Realmz Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000008f0e00004100000000000000,PlaySega,a:b1,b:b0,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b4,y:b3,platform:Windows,
03000000666600006706000000000000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Windows,
03000000e30500009605000000000000,PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
@@ -483,11 +493,13 @@
03000000f0250000c183000000000000,PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000d9040000160f000000000000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
030000004c0500003713000000000000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
-03000000d620000011a7000000000000,PowerA Core Plus GameCube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+03000000d620000011a7000000000000,PowerA Core Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000dd62000015a7000000000000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000d620000012a7000000000000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000dd62000016a7000000000000,PowerA Fusion Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000d620000013a7000000000000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000d62000002640000000000000,PowerA OPS Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000d62000003340000000000000,PowerA OPS Pro Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
0300000062060000d570000000000000,PowerA PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000d620000014a7000000000000,PowerA Spectra Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
@@ -521,28 +533,28 @@
030000008f0e00000300000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
030000008f0e00001431000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000ba2200002010000000000000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Windows,
-03000000120c00000807000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000120c0000111e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000120c0000121e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000120c0000130e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000120c0000150e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000120c0000180e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000120c0000181e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000120c0000191e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000120c00001e0e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000120c0000a957000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000120c0000aa57000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000120c0000f21c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000120c0000f31c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000120c0000f41c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000120c0000f51c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000120c0000f70e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000120e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000160e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-030000001a1e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c00000807000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+03000000120c0000111e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+03000000120c0000121e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+03000000120c0000130e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+03000000120c0000150e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+03000000120c0000180e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+03000000120c0000181e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+03000000120c0000191e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+03000000120c00001e0e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+03000000120c0000a957000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+03000000120c0000aa57000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+03000000120c0000f21c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+03000000120c0000f31c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+03000000120c0000f41c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+03000000120c0000f51c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+03000000120c0000f70e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+03000000120e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+03000000160e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+030000001a1e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
-030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
030000004c0500005f0e000000000000,PS5 Access Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
030000004c050000e60c000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
030000004c050000f20d000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
@@ -557,7 +569,7 @@
03000000300f00001210000000000000,Qanba Joystick Plus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows,
03000000341a00000104000000000000,Qanba Joystick Q4RAF,a:b5,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b1,y:b2,platform:Windows,
03000000222c00000223000000000000,Qanba Obsidian Arcade Stick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
-03000000222c00000023000000000000,Qanba Obsidian Arcade Stick PS4,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000222c00000023000000000000,Qanba Obsidian Arcade Stick PS4,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
030000008a2400006682000000000000,R1 Mobile Controller,a:b3,b:b1,back:b7,leftx:a0,lefty:a1,start:b6,x:b4,y:b0,platform:Windows,
03000000086700006626000000000000,RadioShack,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
03000000ff1100004733000000000000,Ramox FPS Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows,
@@ -585,10 +597,11 @@
030000009b2800002b00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
030000009b2800002c00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
030000009b2800008000000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
+03000000790000008f18000000000000,Rapoo Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000f8270000bf0b000000000000,Razer Kishi,a:b6,b:b7,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b18,leftshoulder:b12,leftstick:b19,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b13,rightstick:b20,righttrigger:b15,rightx:a3,righty:a4,start:b17,x:b9,y:b10,platform:Windows,
03000000321500000204000000000000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
-03000000321500000104000000000000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000321500000104000000000000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000321500000010000000000000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000321500000507000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000321500000707000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
@@ -596,7 +609,7 @@
03000000321500000a10000000000000,Razer Raiju TE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000321500000410000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000321500000910000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000321500000011000000000000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000321500000011000000000000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000321500000009000000000000,Razer Serval,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,leftx:a0,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000921200004547000000000000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b6,x:b3,y:b4,platform:Windows,
03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
@@ -653,7 +666,7 @@
03000000830500006120000000000000,Sanwa Smart Grip II,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,x:b1,y:b3,platform:Windows,
03000000c01100000051000000000000,Satechi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
030000004f04000028b3000000000000,Score A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000952e00002577000000000000,Scuf PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000952e00002577000000000000,Scuf PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000a30c00002500000000000000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows,
03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000d804000086e6000000000000,Sega Multi Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
@@ -663,7 +676,7 @@
03000000b40400000a01000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
030000003b07000004a1000000000000,SFX,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Windows,
03000000f82100001900000000000000,Shogun Bros Chameleon X1,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
-03000000120c00001c1e000000000000,SnakeByte 4S PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c00001c1e000000000000,SnakeByte 4S PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000140300000918000000000000,SNES Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
0300000081170000960a000000000000,SNES Controller,a:b4,b:b0,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b5,y:b1,platform:Windows,
03000000811700009d0a000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
@@ -678,7 +691,7 @@
03000000d11800000094000000000000,Stadia Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b11,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,
03000000de280000fc11000000000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000de280000ff11000000000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
-03000000120c0000160e000000000000,Steel Play Metaltech PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000160e000000000000,Steel Play Metaltech PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000110100001914000000000000,SteelSeries,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000381000001214000000000000,SteelSeries Free,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,
03000000110100003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
@@ -738,10 +751,11 @@
03000000bd12000012d0000000000000,USB Controller,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
03000000ff1100004133000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
03000000632500002305000000000000,USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
+03000000882800000305000000000000,V5 Game Pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,x:b2,y:b3,platform:Windows,
03000000790000001a18000000000000,Venom,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
-030000006f0e00000302000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
-030000006f0e00000702000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00000302000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
+030000006f0e00000702000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:a3,righty:a4,start:b4,x:b2,y:b3,platform:Windows,
03000000120c0000ab57000000000000,Warrior Joypad JS083,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000007e0500003003000000000000,Wii U Pro,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b6,leftstick:b11,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b12,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
@@ -769,7 +783,6 @@
03000000120c00000a88000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a2,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
03000000120c00001088000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2~,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5~,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000002a0600002000000000000000,Xbox Controller,a:b0,b:b1,back:b13,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b5,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b15,righttrigger:b7,rightx:a2,righty:a5,start:b12,x:b2,y:b3,platform:Windows,
-03000000300f00008888000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:b13,dpleft:b10,dpright:b11,dpup:b12,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
03000000380700001645000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
03000000380700002645000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000380700003645000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
@@ -778,7 +791,6 @@
030000005e0400008502000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000005e0400008702000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
030000005e0400008902000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b10,leftstick:b8,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b9,righttrigger:b4,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
-030000000d0f00006300000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000005e0400000c0b000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000005e040000d102000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000005e040000dd02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
@@ -812,6 +824,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Mac OS X,
03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00006a28000000010000,8BitDo GameCube,a:b0,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b9,paddle2:b8,rightshoulder:b10,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b1,y:b4,platform:Mac OS X,
03000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001251000000020000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
@@ -853,6 +866,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000260000001000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001230000000010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00001b30000001000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00001d30000001000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00001530000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00001630000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00001730000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
@@ -871,18 +886,19 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000050b00000579000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b42,paddle1:b9,paddle2:b11,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
03000000050b00000679000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b23,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
+03000000503200000110000045010000,Atari VCS Classic,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b3,start:b2,platform:Mac OS X,
03000000503200000110000047010000,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b3,start:b2,platform:Mac OS X,
03000000503200000210000047010000,Atari VCS Modern Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Mac OS X,
030000008a3500000102000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X,
030000008a3500000201000000010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000008a3500000202000000010000,Backbone One,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X,
030000008a3500000402000000010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
-030000008a3500000302000000010000,Backbone One PlayStationÆ Edition,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X,
+030000008a3500000302000000010000,Backbone One PlayStation Edition,a:b0,b:b1,back:b16,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b17,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b15,x:b2,y:b3,platform:Mac OS X,
03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
03000000c62400001b89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
-03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
-03000000120c0000200e000000010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
-03000000120c0000210e000000010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
+03000000120c0000200e000000010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
+03000000120c0000210e000000010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000d8140000cecf000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X,
@@ -897,7 +913,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000ac0500001a06000002020000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000ad1b000001f9000000000000,Gamestop BB070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
-03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
030000006f0e00000102000000000000,GameStop Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
03000000ff1100003133000007010000,GameWare PC Control Pad,a:b2,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Mac OS X,
030000007d0400000540000001010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -906,13 +922,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f00002d00000000100000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00005f00000000000000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00005f00000000010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
-030000000d0f00005e00000000000000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
-030000000d0f00005e00000000010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00005e00000000000000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00005e00000000010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
030000000d0f00008400000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00008500000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000341a00000302000014010000,Hori Fighting Stick Mini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00008800000000010000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
-030000000d0f00008700000000010000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00008700000000010000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
030000000d0f00004d00000000000000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00003801000008010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Mac OS X,
030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -920,7 +936,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f00000002000017010000,Hori Split Pad Fit,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00000002000015010000,Hori Switch Split Pad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00006e00000000010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
-030000000d0f00006600000000010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00006600000000010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
030000000d0f00006600000000000000,Horipad FPS Plus 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f0000ee00000000010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f0000c100000072050000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -943,8 +959,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006d04000018c2000000010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3~,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000380700005032000000010000,Mad Catz PS3 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
-03000000380700005082000000010000,Mad Catz PS4 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
-03000000380700008483000000010000,Mad Catz PS4 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000380700005082000000010000,Mad Catz PS4 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
+03000000380700008483000000010000,Mad Catz PS4 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
03000000790000000600000007010000,Marvo GT-004,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
030000008f0e00001330000011010000,Mayflash Controller Adapter,a:b2,b:b4,back:b16,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b12,lefttrigger:b16,leftx:a0,lefty:a2,rightshoulder:b14,rightx:a6~,righty:a4,start:b18,x:b0,y:b6,platform:Mac OS X,
03000000790000004318000000010000,Mayflash GameCube Adapter,a:b4,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X,
@@ -988,10 +1004,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,
030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,
030000004c0500006802000072050000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X,
-030000004c050000a00b000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
-030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
-030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
-030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000004c050000a00b000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
+030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
+030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
+030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
0300004b4c0500005f0e000000010000,PS5 Access Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
030000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
030000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
@@ -1004,10 +1020,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000009b2800008000000022020000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Mac OS X,
030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
03000000321500000204000000010000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
-03000000321500000104000000010000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000321500000104000000010000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
03000000321500000010000000010000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000321500000507000001010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
-03000000321500000011000000010000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+03000000321500000011000000010000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
03000000321500000009000000020000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,
030000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,
0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
@@ -1031,8 +1047,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000b40400000a01000000000000,Sega Saturn,a:b0,b:b1,back:b5,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,
030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X,
-030000004c050000a00b000000000000,Sony DualShock 4 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
-030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000004c050000a00b000000000000,Sony DualShock 4 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
+030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
03000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,
030000005e0400008e02000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
@@ -1062,8 +1078,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X,
03000000632500002605000000010000,Uberwith Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000151900005678000010010000,Uniplay U6,a:b3,b:b6,back:b25,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,leftstick:b31,lefttrigger:b21,leftx:a1,lefty:a3,rightshoulder:b19,rightstick:b33,righttrigger:b23,rightx:a4,righty:a5,start:b27,x:b11,y:b13,platform:Mac OS X,
-030000006f0e00000302000025040000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
-030000006f0e00000702000003060000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000006f0e00000302000025040000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
+030000006f0e00000702000003060000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X,
050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X,
030000005e0400008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
@@ -1078,7 +1094,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e040000d102000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000dd02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000e002000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,
-030000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,
030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
@@ -1088,7 +1104,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000005e040000130b000007050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000130b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000005e040000130b000022050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000120c0000100e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -1096,10 +1114,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
# Linux
03000000c82d00000031000011010000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00000631000000010000,8BitDo Adapter 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux,
03000000021000000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00006a28000000010000,8BitDo GameCube,a:b0,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b9,paddle2:b8,rightshoulder:b10,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b1,y:b4,platform:Linux,
03000000c82d00001251000011010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00001151000011010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
@@ -1107,11 +1127,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00000650000011010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000c82d00005106000000010000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00000a20000000020000,8BitDo M30 Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,
03000000c82d00002090000011010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00002090000000010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux,
03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00006928000011010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Linux,
05000000c82d00006928000000010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Linux,
05000000c82d00002590000001000000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000008000000210000011010000,8BitDo NES30,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
@@ -1133,6 +1155,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000331000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000431000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00002867000000010000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b3,y:b4,platform:Linux,
+03000000c82d00000060000011010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000060000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000061000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
030000003512000012ab000010010000,8BitDo SFC30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux,
@@ -1151,12 +1174,16 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000202800000900000000010000,8BitDo SNES30,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00001230000000010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00000a31000014010000,8BitDo Ultimate 2C,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000c82d00001d30000011010000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000c82d00001b30000001000000,8BitDo Ultimate 2C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b5,paddle2:b2,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001530000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001630000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001730000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001130000011010000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00000631000010010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c82d00000760000011010000,8BitDo Ultimate Wireless,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
-03000000c82d00001230000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00001230000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001330000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00000631000014010000,8BitDo Ultimate Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c82d00000121000011010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
@@ -1164,7 +1191,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000a00500003232000001000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
05000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
-050000005e040000e002000030110000,8BitDo Zero 2,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c01100000355000011010000,Acrux Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e00008801000011010000,Afterglow Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
@@ -1201,7 +1227,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000008a3500000302000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000008a3500000402000011010000,Backbone One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c62400001b89000011010000,BDA MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
-03000000d62000002a79000011010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000d62000002a79000011010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
03000000c21100000791000011010000,Be1 GC101 Controller 1.03,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000c31100000791000011010000,Be1 GC101 Controller 1.03,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000005e0400008e02000003030000,Be1 GC101 Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1209,14 +1235,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000bc2000000055000001000000,Betop AX1 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000bc2000006412000011010000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b30,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000006b1400000209000011010000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-03000000120c0000200e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
-03000000120c0000210e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000120c0000200e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
+03000000120c0000210e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
03000000120c0000f70e000011010000,Brook Universal Fighting Board,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000af1e00002400000010010000,Clockwork Pi DevTerm,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b9,x:b3,y:b0,platform:Linux,
030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux,
03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux,
03000000a306000022f6000011010000,Cyborg V3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
+030000005e0400008e02000002010000,Data Frog S80,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,
03000000791d00000103000010010000,Dual Box Wii Classic Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000c11100000191000011010000,EasySMX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
@@ -1260,17 +1287,16 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
06000000adde0000efbe000002010000,Hidromancer Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d81400000862000011010000,HitBox PS3 PC Analog Mode,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux,
03000000c9110000f055000011010000,HJC Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
-030000000d0f00000d00000000010000,Hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,rightshoulder:b7,start:b9,x:b1,y:b2,platform:Linux,
030000000d0f00006d00000020010000,Hori EDGE 301,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:+a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000000d0f00008400000011010000,Hori Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00005f00000011010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-030000000d0f00005e00000011010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00005e00000011010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000000d0f00005001000009040000,Hori Fighting Commander OCTA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000000d0f00008500000010010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00008600000002010000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000000d0f00003701000013010000,Hori Fighting Stick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b3,y:b2,platform:Linux,
030000000d0f00008800000011010000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
-030000000d0f00008700000011010000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,rightstick:b11,righttrigger:a4,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00008700000011010000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,rightstick:b11,righttrigger:a4,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000000d0f00001000000011010000,Hori Fightstick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
03000000ad1b000003f5000033050000,Hori Fightstick VX,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b8,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
030000000d0f00004d00000011010000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
@@ -1286,7 +1312,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f00008501000017010000,Hori Split Pad Fit,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000000d0f00008501000015010000,Hori Switch Split Pad Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000000d0f00006e00000011010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-030000000d0f00006600000011010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00006600000011010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000000d0f0000ee00000011010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f0000c100000011010000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00006700000001010000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1337,12 +1363,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000380700006652000025010000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000380700008532000010010000,Mad Catz Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
03000000380700005032000011010000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-03000000380700005082000011010000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000380700005082000011010000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,
03000000380700008034000011010000,Mad Catz Fightstick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-03000000380700008084000011010000,Mad Catz Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000380700008084000011010000,Mad Catz Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
03000000380700008433000011010000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-03000000380700008483000011010000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000380700008483000011010000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
03000000380700001888000010010000,Mad Catz Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000380700003888000010010000,Mad Catz Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000380700001647000010040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1385,6 +1411,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000050b000003090000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e0400008e02000030110000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b00000b050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+060000005e040000120b000001050000,Microsoft Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
03000000790000001c18000010010000,Mobapad Chitu HD,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000004d4f435554452d3035335800,Mocute 053X,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
@@ -1398,9 +1425,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000c62400001a89000000010000,MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000250900006688000000010000,MP8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
030000005e0400008e02000010020000,MSI GC20 V2,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000f70600000100000000010000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Linux,
+030000006f0e00001311000011010000,N64 Controller,+rightx:b10,+righty:b3,-rightx:b0,-righty:b11,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,platform:Linux,
030000006b1400000906000014010000,Nacon Asymmetric Wireless PS4 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006b140000010c000010010000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
03000000853200000706000012010000,Nacon GC-100,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+0300000085320000170d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
+0300000085320000190d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000004f1f00000800000011010000,NeoGeo PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
0300000092120000474e000000010000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Linux,
@@ -1461,7 +1492,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000004c0500003713000011010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
-03000000d620000011a7000011010000,PowerA Core Plus Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+03000000d620000011a7000011010000,PowerA Core Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000dd62000015a7000011010000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000d620000012a7000011010000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000d62000000140000001010000,PowerA Fusion Pro 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1476,7 +1507,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c62400001a54000001010000,PowerA Xbox One Mini Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000240000001010000,PowerA Xbox One Spectra Infinity,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000f20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000d62000000b20000001010000,PowerA Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+03000000250900000017000010010000,PS/SS/N64 Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b5,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2~,righty:a3,start:b8,platform:Linux,
03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000004c0500006802000010010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,
@@ -1492,18 +1525,18 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000004c0500006802000000810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
05000000504c415953544154494f4e00,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,
060000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux,
-030000004c050000a00b000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000004c050000a00b000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000004c050000a00b000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
-030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000004c050000c405000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
-030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
-030000004c050000cc09000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
+030000004c050000cc09000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000004c050000cc09000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
-03000000c01100000140000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
-050000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000c01100000140000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
+050000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
050000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
050000004c050000c405000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
-050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
050000004c050000cc09000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
0300004b4c0500005f0e000011010000,PS5 Access Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
@@ -1515,25 +1548,29 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
03000000300f00001211000011010000,Qanba Arcade Joystick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux,
03000000222c00000225000011010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-03000000222c00000025000011010000,Qanba Dragon Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
-03000000222c00000020000011010000,Qanba Drone Arcade PS4 Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Linux,
+03000000222c00000025000011010000,Qanba Dragon Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
+03000000222c00001220000011010000,Qanba Drone 2 Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000222c00001020000011010000,Qanba Drone 2 Arcade Joystick (PS5),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000222c00000020000011010000,Qanba Drone Arcade PS4 Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
03000000300f00001210000010010000,Qanba Joystick Plus,a:b0,b:b1,back:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,start:b9,x:b2,y:b3,platform:Linux,
03000000222c00000223000011010000,Qanba Obsidian Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000009b2800000300000001010000,Raphnet 4nes4snes,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,
030000009b2800004200000001010000,Raphnet Dual NES Adapter,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Linux,
+0300132d9b2800006500000000000000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
+0300132d9b2800006500000001010000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
030000009b2800003200000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
030000009b2800006000000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
030000009b2800008000000020020000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Linux,
03000000f8270000bf0b000011010000,Razer Kishi,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000321500000204000011010000,Razer Panthera PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-03000000321500000104000011010000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
-03000000321500000810000011010000,Razer Panthera PS4 Evo Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000321500000104000011010000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
+03000000321500000810000011010000,Razer Panthera PS4 Evo Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
03000000321500000010000011010000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000321500000507000000010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000321500000a10000001000000,Razer Raiju Tournament Edition,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
-03000000321500000011000011010000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000321500000011000011010000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000008916000000fe000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c6240000045d000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1541,6 +1578,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000321500000b10000011010000,Razer Wolverine PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
+030000000d0f0000c100000010010000,Retro Bit Legacy16,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b12,leftshoulder:b4,lefttrigger:b6,misc1:b13,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f0000c100000072056800,Retro Bit Legacy16,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b5,leftshoulder:b9,lefttrigger:+a4,misc1:b11,rightshoulder:b10,righttrigger:+a5,start:b6,x:b3,y:b2,platform:Linux,
03000000790000001100000010010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Linux,
0300000003040000c197000011010000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,
190000004b4800000111000000010000,RetroGame Joypad,a:b1,b:b0,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
@@ -1567,6 +1606,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000a306000020f6000011010000,Saitek PS2700 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
05000000e804000000a000001b010000,Samsung EIGP20,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000d81d00000e00000010010000,Savior,a:b0,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b9,x:b4,y:b5,platform:Linux,
+03000000952e00004b43000011010000,Scuf Envision,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux,
+03000000952e00004d43000011010000,Scuf Envision,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux,
+03000000952e00004e43000011010000,Scuf Envision,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux,
03000000a30c00002500000011010000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Linux,
03000000790000001100000011010000,Sega Saturn,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Linux,
03000000790000002201000011010000,Sega Saturn,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
@@ -1578,7 +1620,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000bc2000000055000010010000,Shanwan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000f025000021c1000010010000,Shanwan Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000341a00000908000010010000,SL6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
-050000004c050000cc09000001000000,Sony DualShock 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+030000004b2900000430000011000000,Snakebyte Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+050000004c050000cc09000001000000,Sony DualShock 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
03000000ff000000cb01000010010000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
03000000250900000500000000010000,Sony PS2 pad with SmartJoy Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
030000005e0400008e02000073050000,Speedlink Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1648,8 +1691,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
03000000790000000600000007010000,USB gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux,
03000000790000001100000000010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux,
-030000006f0e00000302000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
-030000006f0e00000702000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+030000006f0e00000302000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
+030000006f0e00000702000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
05000000ac0500003232000001000000,VR Box Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
05000000434f4d4d414e440000000000,VX Gaming Command Series,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
0000000058626f782033363020576900,Xbox 360 Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux,
@@ -1660,6 +1703,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e040000a102000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000a102000007010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000a102000030060000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006f0e00001503000000020000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e0400008e02000000010000,Xbox 360 EasySMX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000a102000014010000,Xbox 360 Receiver,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e0400000202000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
@@ -1679,12 +1723,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e040000ea02000011050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000ea0200000b050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000ea0200000d050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+060000005e040000ea02000016050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000001050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000005050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000009050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
-030000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000120b000015050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
@@ -1696,10 +1742,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
060000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000120b00000b050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
-050000005e040000130b000017050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
-060000005e040000120b00000d050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000014050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+050000005e040000130b000017050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+060000005e040000120b00000d050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000200b000013050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000200b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
@@ -1712,181 +1758,184 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000120c0000101e000011010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
# Android
-38653964633230666463343334313533,8BitDo Adapter,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-36666264316630653965636634386234,8BitDo Adapter 2,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38653964633230666463343334313533,8BitDo Adapter,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+36666264316630653965636634386234,8BitDo Adapter 2,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
38426974446f20417263616465205374,8BitDo Arcade Stick,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b5,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-61393962646434393836356631636132,8BitDo Arcade Stick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
-64323139346131306233636562663738,8BitDo Arcade Stick,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
-64643565386136613265663236636564,8BitDo Arcade Stick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
-33313433353539306634656436353432,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-38426974446f20446f67626f6e65204d,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android,
-34343439373236623466343934376233,8BitDo FC30 Pro,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b28,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b29,righttrigger:b7,start:b5,x:b30,y:b2,platform:Android,
-38426974446f2038426974446f204c69,8BitDo Lite,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-30643332373663313263316637356631,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-38426974446f204c6974652032000000,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-62656331626461363634633735353032,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-38393936616436383062666232653338,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-38426974446f204c6974652053450000,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-39356430616562366466646636643435,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+61393962646434393836356631636132,8BitDo Arcade Stick,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
+64323139346131306233636562663738,8BitDo Arcade Stick,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
+64643565386136613265663236636564,8BitDo Arcade Stick,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
+33313433353539306634656436353432,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38426974446f20446f67626f6e65204d,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android,
+34343439373236623466343934376233,8BitDo FC30 Pro,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b28,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b29,righttrigger:b7,start:b5,x:b30,y:b2,platform:Android,
+38426974446f204e4743204d6f646b69,8BitDo GameCube,a:b0,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b18,paddle2:b17,rightshoulder:b15,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b1,y:b3,platform:Android,
+38426974446f2038426974446f204c69,8BitDo Lite,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+30643332373663313263316637356631,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f204c6974652032000000,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+62656331626461363634633735353032,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38393936616436383062666232653338,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f204c6974652053450000,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+39356430616562366466646636643435,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000006500000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a5,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000051060000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,platform:Android,
-32323161363037623637326438643634,8BitDo M30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-33656266353630643966653238646264,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,start:b10,x:b19,y:b2,platform:Android,
-38426974446f204d3330204d6f646b69,8BitDo M30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-39366630663062373237616566353437,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,start:b6,x:b2,y:b3,platform:Android,
-64653533313537373934323436343563,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,start:b6,x:b2,y:b3,platform:Android,
-66356438346136366337386437653934,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,start:b18,x:b19,y:b2,platform:Android,
-66393064393162303732356665666366,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b2,y:b3,platform:Android,
-38426974446f204d6963726f2067616d,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,platform:Android,
-61653365323561356263373333643266,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,platform:Android,
-62613137616239666338343866326336,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,platform:Android,
-33663431326134333366393233616633,8BitDo N30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android,
-38426974446f204e3330204d6f646b69,8BitDo N30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android,
+32323161363037623637326438643634,8BitDo M30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+33656266353630643966653238646264,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,start:b10,x:b19,y:b2,platform:Android,
+38426974446f204d3330204d6f646b69,8BitDo M30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+39366630663062373237616566353437,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,start:b6,x:b2,y:b3,platform:Android,
+64653533313537373934323436343563,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,start:b6,x:b2,y:b3,platform:Android,
+66356438346136366337386437653934,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,start:b18,x:b19,y:b2,platform:Android,
+66393064393162303732356665666366,8BitDo M30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b2,y:b3,platform:Android,
+38426974446f204d6963726f2067616d,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,platform:Android,
+61653365323561356263373333643266,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,platform:Android,
+62613137616239666338343866326336,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,platform:Android,
+33663431326134333366393233616633,8BitDo N30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android,
+38426974446f204e3330204d6f646b69,8BitDo N30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android,
05000000c82d000015900000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000065280000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-38323035343766666239373834336637,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,platform:Android,
-38426974446f204e3634204d6f646b69,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,platform:Android,
-32363135613966656338666638666237,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-35363534633333373639386466346631,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-38426974446f204e454f47454f204750,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-39383963623932353561633733306334,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38323035343766666239373834336637,8BitDo N64,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,platform:Android,
+38426974446f204e3634204d6f646b69,8BitDo N64,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,platform:Android,
+32363135613966656338666638666237,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+35363534633333373639386466346631,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38426974446f204e454f47454f204750,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+39383963623932353561633733306334,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000000220000000900000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
050000002038000009000000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-38313433643131656262306631373166,8BitDo P30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-38326536643339353865323063616339,8BitDo P30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-38426974446f2050333020636c617373,8BitDo P30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-35376664343164386333616535333434,8BitDo Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,start:b10,x:b19,y:b2,platform:Android,
-38426974446f2038426974446f205072,8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-38426974446f2050726f203200000000,8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-62373739366537363166326238653463,8BitDo Pro 2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b3,y:b2,platform:Android,
-38386464613034326435626130396565,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-38426974446f2038426974446f205265,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-66303230343038613365623964393766,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-38426974446f20533330204d6f646b69,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-66316462353561376330346462316137,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38313433643131656262306631373166,8BitDo P30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38326536643339353865323063616339,8BitDo P30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38426974446f2050333020636c617373,8BitDo P30,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+35376664343164386333616535333434,8BitDo Pro 2,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,start:b10,x:b19,y:b2,platform:Android,
+38426974446f2038426974446f205072,8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f2050726f203200000000,8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+61333362366131643730353063616330,8BitDo Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+62373739366537363166326238653463,8BitDo Pro 2,a:b1,b:b0,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b3,y:b2,platform:Android,
+38386464613034326435626130396565,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f2038426974446f205265,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+66303230343038613365623964393766,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f20533330204d6f646b69,8BitDo S30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+66316462353561376330346462316137,8BitDo S30,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
05000000c82d000000600000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000000610000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-38426974646f20534633302050726f00,8BitDo SF30 Pro,a:b1,b:b0,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b17,platform:Android,
+38426974646f20534633302050726f00,8BitDo SF30 Pro,a:b1,b:b0,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b17,platform:Android,
61623334636338643233383735326439,8BitDo SFC30,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b31,start:b5,x:b30,y:b2,platform:Android,
05000000c82d000012900000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000062280000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
-38316230613931613964356666353839,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-38426974446f20534e3330204d6f646b,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-65323563303231646531383162646335,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-35383531346263653330306238353131,8BitDo SN30 PP,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38316230613931613964356666353839,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f20534e3330204d6f646b,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+65323563303231646531383162646335,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+35383531346263653330306238353131,8BitDo SN30 PP,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
05000000c82d000001600000ffff3f00,8BitDo SN30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000002600000ffff0f00,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-36653638656632326235346264663661,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
-38303232393133383836366330346462,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
-38346630346135363335366265656666,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-38426974446f20534e33302050726f2b,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-536f6e7920436f6d707574657220456e,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-66306331643531333230306437353936,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+36653638656632326235346264663661,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
+38303232393133383836366330346462,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
+38346630346135363335366265656666,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f20534e33302050726f2b,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+536f6e7920436f6d707574657220456e,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+66306331643531333230306437353936,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
050000002028000009000000ffff3f00,8BitDo SNES30,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
050000003512000020ab000000780f00,8BitDo SNES30,a:b21,b:b20,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b24,y:b23,platform:Android,
33666663316164653937326237613331,8BitDo Zero,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android,
38426974646f205a65726f2047616d65,8BitDo Zero,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android,
05000000c82d000018900000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
-33663434393362303033616630346337,8BitDo Zero 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
-34656330626361666438323266633963,8BitDo Zero 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android,
-63396666386564393334393236386630,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
-63633435623263373466343461646430,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android,
-32333634613735616163326165323731,Amazon Luna Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,
-4c696e757820342e31392e3137322077,Anbernic Gamepad,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a4,start:b6,x:b2,y:b3,platform:Android,
+33663434393362303033616630346337,8BitDo Zero 2,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
+34656330626361666438323266633963,8BitDo Zero 2,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android,
+63396666386564393334393236386630,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
+63633435623263373466343461646430,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android,
+32333634613735616163326165323731,Amazon Luna Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,
+4c696e757820342e31392e3137322077,Anbernic Gamepad,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a4,start:b6,x:b2,y:b3,platform:Android,
417374726f2063697479206d696e6920,Astro City Mini,a:b23,b:b22,back:b29,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android,
-35643263313264386134376362363435,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,start:b6,platform:Android,
-32353831643566306563643065356239,Atari VCS Modern Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-32303165626138343962363666346165,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+35643263313264386134376362363435,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,start:b6,platform:Android,
+32353831643566306563643065356239,Atari VCS Modern Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+4f64696e20436f6e74726f6c6c657200,AYN Odin,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b14,dpright:b13,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:+a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+32303165626138343962363666346165,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
38383337343564366131323064613561,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
-34313430343161653665353737323365,Elecom JC-W01U,a:b23,b:b24,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android,
-4875694a6961204a432d573031550000,Elecom JC-W01U,a:b23,b:b24,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android,
-30363230653635633863366338623265,Evo VR,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,x:b2,y:b3,platform:Android,
+34313430343161653665353737323365,Elecom JC-W01U,a:b23,b:b24,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android,
+4875694a6961204a432d573031550000,Elecom JC-W01U,a:b23,b:b24,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android,
+30363230653635633863366338623265,Evo VR,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,x:b2,y:b3,platform:Android,
05000000b404000011240000dfff3f00,Flydigi Vader 2,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-34323662653333636330306631326233,Google Nexus,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-35383633353935396534393230616564,Google Stadia Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+34323662653333636330306631326233,Google Nexus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+35383633353935396534393230616564,Google Stadia Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
05000000d6020000e5890000dfff3f00,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,
05000000d6020000e5890000dfff3f80,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a3,rightx:a4,righty:a5,start:b6,x:b2,y:b3,platform:Android,
-66633030656131663837396562323935,Hori Battle,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
-35623466343433653739346434636330,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
-484f524920434f2e2c4c54442e203130,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
-484f524920434f2e2c4c544420205041,Hori Gem Pad 3,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,platform:Android,
-65656436646661313232656661616130,Hori PC Engine Mini Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b18,platform:Android,
-31303433326562636431653534636633,Hori Real Arcade Pro 3,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
-32656664353964393561366362333636,Hori Switch Split Pad Pro,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
-30306539356238653637313730656134,HORIPAD Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
+66633030656131663837396562323935,Hori Battle,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
+35623466343433653739346434636330,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+484f524920434f2e2c4c54442e203130,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+484f524920434f2e2c4c544420205041,Hori Gem Pad 3,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,platform:Android,
+65656436646661313232656661616130,Hori PC Engine Mini Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,start:b18,platform:Android,
+31303433326562636431653534636633,Hori Real Arcade Pro 3,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+32656664353964393561366362333636,Hori Switch Split Pad Pro,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
+30306539356238653637313730656134,HORIPAD Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
48797065726b696e2050616400000000,Hyperkin Admiral N64 Controller,+rightx:b6,+righty:b7,-rightx:b17,-righty:b5,a:b1,b:b0,leftshoulder:b3,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,platform:Android,
62333331353131353034386136626636,Hyperkin Admiral N64 Controller,+rightx:b6,+righty:b7,-rightx:b17,-righty:b5,a:b1,b:b0,leftshoulder:b3,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,platform:Android,
-31306635363562663834633739396333,Hyperkin N64 Adapter,a:b1,b:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android,
-5368616e57616e202020202048797065,Hyperkin N64 Adapter,a:b1,b:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android,
+31306635363562663834633739396333,Hyperkin N64 Adapter,a:b1,b:b19,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android,
+5368616e57616e202020202048797065,Hyperkin N64 Adapter,a:b1,b:b19,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android,
0500000083050000602000000ffe0000,iBuffalo SNES Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b15,rightshoulder:b16,start:b10,x:b2,y:b3,platform:Android,
-5553422c322d6178697320382d627574,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,rightshoulder:b18,start:b10,x:b3,y:b2,platform:Android,
+5553422c322d6178697320382d627574,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b17,rightshoulder:b18,start:b10,x:b3,y:b2,platform:Android,
64306137363261396266353433303531,InterAct GoPad,a:b24,b:b25,leftshoulder:b23,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,x:b21,y:b22,platform:Android,
-532e542e442e20496e74657261637420,InterAct HammerHead FX,a:b23,b:b24,back:b30,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b22,lefttrigger:b28,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b25,righttrigger:b29,rightx:a2,righty:a3,start:b31,x:b20,y:b21,platform:Android,
-65346535636333663931613264643164,Joy-Con,a:b21,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b23,y:b24,platform:Android,
-33346566643039343630376565326335,Joy-Con (L),a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android,
-35313531613435623366313835326238,Joy-Con (L),a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android,
-4a6f792d436f6e20284c290000000000,Joy-Con (L),a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android,
-38383665633039363066383334653465,Joy-Con (R),a:b0,b:b1,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
-39363561613936303237333537383931,Joy-Con (R),a:b0,b:b1,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
-4a6f792d436f6e202852290000000000,Joy-Con (R),a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
-39656136363638323036303865326464,JYS Aapter,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
-63316564383539663166353034616434,JYS Adapter,a:b1,b:b3,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b0,y:b2,platform:Android,
-64623163333561643339623235373232,Logitech F310,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-35623364393661626231343866613337,Logitech F710,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-4c6f6769746563682047616d65706164,Logitech F710,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-64396331333230326333313330336533,Logitech F710,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-39653365373864633935383236363438,Logitech G Cloud,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-416d617a6f6e2047616d6520436f6e74,Luna Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
-4c756e612047616d6570616400000000,Luna Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-30363066623539323534363639323363,Magic NS,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
-31353762393935386662336365626334,Magic NS,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
-39623565346366623931666633323530,Magic NS,a:b1,b:b3,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b0,y:b2,platform:Android,
-6d6179666c617368206c696d69746564,Mayflash GameCube Adapter,a:b22,b:b21,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a5,righty:a2,start:b30,x:b23,y:b24,platform:Android,
-436f6e74726f6c6c6572000000000000,Mayflash N64 Adapter,a:b1,b:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android,
-65666330633838383061313633326461,Mayflash N64 Adapter,a:b1,b:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android,
-37316565396364386635383230353365,Mayflash Saturn Adapter,a:b21,b:b22,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android,
-4875694a696120205553422047616d65,Mayflash Saturn Adapter,a:b21,b:b22,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android,
-535a4d792d706f776572204c54442043,Mayflash Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b31,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android,
-30653962643666303631376438373532,Mayflash Wii DolphinBar,a:b23,b:b24,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b0,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android,
-39346131396233376535393665363161,Mayflash Wii U Pro Adapter,a:b22,b:b23,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,leftstick:b31,lefttrigger:b27,rightshoulder:b26,rightstick:b0,righttrigger:b28,rightx:a0,righty:a1,start:b30,x:b21,y:b24,platform:Android,
+532e542e442e20496e74657261637420,InterAct HammerHead FX,a:b23,b:b24,back:b30,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,leftstick:b22,lefttrigger:b28,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b25,righttrigger:b29,rightx:a2,righty:a3,start:b31,x:b20,y:b21,platform:Android,
+65346535636333663931613264643164,Joy-Con,a:b21,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b23,y:b24,platform:Android,
+33346566643039343630376565326335,Joy-Con (L),a:b0,b:b1,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android,
+35313531613435623366313835326238,Joy-Con (L),a:b0,b:b1,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android,
+4a6f792d436f6e20284c290000000000,Joy-Con (L),a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android,
+38383665633039363066383334653465,Joy-Con (R),a:b0,b:b1,back:b5,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
+39363561613936303237333537383931,Joy-Con (R),a:b0,b:b1,back:b5,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
+4a6f792d436f6e202852290000000000,Joy-Con (R),a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
+39656136363638323036303865326464,JYS Aapter,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+63316564383539663166353034616434,JYS Adapter,a:b1,b:b3,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b0,y:b2,platform:Android,
+64623163333561643339623235373232,Logitech F310,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+35623364393661626231343866613337,Logitech F710,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+4c6f6769746563682047616d65706164,Logitech F710,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+64396331333230326333313330336533,Logitech F710,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+39653365373864633935383236363438,Logitech G Cloud,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+416d617a6f6e2047616d6520436f6e74,Luna Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
+4c756e612047616d6570616400000000,Luna Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+30363066623539323534363639323363,Magic NS,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+31353762393935386662336365626334,Magic NS,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+39623565346366623931666633323530,Magic NS,a:b1,b:b3,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b0,y:b2,platform:Android,
+6d6179666c617368206c696d69746564,Mayflash GameCube Adapter,a:b22,b:b21,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a5,righty:a2,start:b30,x:b23,y:b24,platform:Android,
+436f6e74726f6c6c6572000000000000,Mayflash N64 Adapter,a:b1,b:b19,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android,
+65666330633838383061313633326461,Mayflash N64 Adapter,a:b1,b:b19,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android,
+37316565396364386635383230353365,Mayflash Saturn Adapter,a:b21,b:b22,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android,
+4875694a696120205553422047616d65,Mayflash Saturn Adapter,a:b21,b:b22,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android,
+535a4d792d706f776572204c54442043,Mayflash Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b31,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android,
+30653962643666303631376438373532,Mayflash Wii DolphinBar,a:b23,b:b24,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b0,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android,
+39346131396233376535393665363161,Mayflash Wii U Pro Adapter,a:b22,b:b23,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,leftstick:b31,lefttrigger:b27,rightshoulder:b26,rightstick:b0,righttrigger:b28,rightx:a0,righty:a1,start:b30,x:b21,y:b24,platform:Android,
31323564663862633234646330373138,Mega Drive,a:b23,b:b22,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android,
-37333564393261653735306132613061,Mega Drive,a:b21,b:b22,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android,
-64363363336633363736393038313464,Mega Drive,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Android,
-33323763323132376537376266393366,Microsoft Dual Strike,a:b24,b:b23,back:b25,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b29,rightshoulder:b78,rightx:a0,righty:a1~,start:b26,x:b22,y:b21,platform:Android,
+37333564393261653735306132613061,Mega Drive,a:b21,b:b22,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android,
+64363363336633363736393038313464,Mega Drive,a:b1,b:b0,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,start:b9,x:b2,y:b3,platform:Android,
+33323763323132376537376266393366,Microsoft Dual Strike,a:b24,b:b23,back:b25,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b27,lefttrigger:b29,rightshoulder:b78,rightx:a0,righty:a1~,start:b26,x:b22,y:b21,platform:Android,
30306461613834333439303734316539,Microsoft SideWinder Pro,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b20,lefttrigger:b9,rightshoulder:b19,righttrigger:b10,start:b17,x:b2,y:b3,platform:Android,
-32386235353630393033393135613831,Microsoft Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-4d4f42415041442050726f2d48440000,Mobapad Chitu HD,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-4d4f435554452d303533582d4d35312d,Mocute 053X,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-33343361376163623438613466616531,Mocute M053,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-39306635663061636563316166303966,Mocute M053,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+32386235353630393033393135613831,Microsoft Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+4d4f42415041442050726f2d48440000,Mobapad Chitu HD,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+4d4f435554452d303533582d4d35312d,Mocute 053X,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+33343361376163623438613466616531,Mocute M053,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+39306635663061636563316166303966,Mocute M053,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Android,
050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b17,y:b2,platform:Android,
34323437396534643531326161633738,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,misc1:b5,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-50726f20436f6e74726f6c6c65720000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b2,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b10,rightx:a2,righty:a3,start:b18,y:b3,platform:Android,
-36326533353166323965623661303933,NSO N64 Controller,+rightx:b17,+righty:b10,-rightx:b2,-righty:b19,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,righttrigger:b15,start:b18,platform:Android,
-4e363420436f6e74726f6c6c65720000,NSO N64 Controller,+rightx:b17,+righty:b10,-rightx:b2,-righty:b19,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,righttrigger:b15,start:b18,platform:Android,
-534e455320436f6e74726f6c6c657200,NSO SNES Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
-64623863346133633561626136366634,NSO SNES Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
+50726f20436f6e74726f6c6c65720000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b2,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b10,rightx:a2,righty:a3,start:b18,y:b3,platform:Android,
+36326533353166323965623661303933,NSO N64 Controller,+rightx:b17,+righty:b10,-rightx:b2,-righty:b19,a:b1,b:b0,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,righttrigger:b15,start:b18,platform:Android,
+4e363420436f6e74726f6c6c65720000,NSO N64 Controller,+rightx:b17,+righty:b10,-rightx:b2,-righty:b19,a:b1,b:b0,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,righttrigger:b15,start:b18,platform:Android,
+534e455320436f6e74726f6c6c657200,NSO SNES Controller,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
+64623863346133633561626136366634,NSO SNES Controller,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android,
050000005509000003720000cf7f3f00,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000005509000010720000ffff3f00,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000005509000014720000df7f3f00,NVIDIA Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,
050000005509000014720000df7f3f80,NVIDIA Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a3,rightx:a4,righty:a5,start:b6,x:b2,y:b3,platform:Android,
-37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
39383335313438623439373538343266,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b16,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,x:b1,y:b19,platform:Android,
4f5559412047616d6520436f6e74726f,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b6,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b19,platform:Android,
-506572666f726d616e63652044657369,PDP PS3 Rock Candy Controller,a:b1,b:b17,back:h0.2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,platform:Android,
+506572666f726d616e63652044657369,PDP PS3 Rock Candy Controller,a:b1,b:b17,back:h0.2,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,platform:Android,
62653335326261303663356263626339,PlayStation Classic Controller,a:b19,b:b1,back:b17,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,lefttrigger:b3,rightshoulder:b10,righttrigger:b20,start:b18,x:b2,y:b0,platform:Android,
-536f6e7920496e746572616374697665,PlayStation Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-576972656c65737320436f6e74726f6c,PlayStation Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-61653962353232366130326530363061,Pokken,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,rightshoulder:b20,righttrigger:b10,start:b18,x:b0,y:b2,platform:Android,
-32666633663735353234363064386132,PS2,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a3,righty:a2,start:b30,x:b24,y:b21,platform:Android,
+536f6e7920496e746572616374697665,PlayStation Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+576972656c65737320436f6e74726f6c,PlayStation Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+61653962353232366130326530363061,Pokken,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,rightshoulder:b20,righttrigger:b10,start:b18,x:b0,y:b2,platform:Android,
+32666633663735353234363064386132,PS2,a:b23,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a3,righty:a2,start:b30,x:b24,y:b21,platform:Android,
050000004c05000068020000dfff3f00,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
536f6e7920504c415953544154494f4e,PS3 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-61363034663839376638653463633865,PS3 Controller,a:b0,b:b1,back:b15,dpdown:a14,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+61363034663839376638653463633865,PS3 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
66366539656564653432353139356536,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
66383132326164626636313737373037,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000004c050000c405000000783f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
@@ -1895,89 +1944,89 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000004c050000c4050000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000004c050000cc090000fffe3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000004c050000cc090000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-30303839663330346632363232623138,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
-31326235383662333266633463653332,PS4 Controller,a:b1,b:b16,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b17,x:b0,y:b2,platform:Android,
-31373231336561636235613666323035,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-31663838336334393132303338353963,PS4 Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-34613139376634626133336530386430,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
-37626233336235343937333961353732,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-37626464343430636562316661643863,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-38393161636261653636653532386639,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-63313733393535663339656564343962,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-63393662363836383439353064663939,PS4 Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-65366465656364636137653363376531,PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
-66613532303965383534396638613230,PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
+30303839663330346632363232623138,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
+31326235383662333266633463653332,PS4 Controller,a:b1,b:b16,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b17,x:b0,y:b2,platform:Android,
+31373231336561636235613666323035,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+31663838336334393132303338353963,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+34613139376634626133336530386430,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
+37626233336235343937333961353732,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+37626464343430636562316661643863,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38393161636261653636653532386639,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+63313733393535663339656564343962,PS4 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+63393662363836383439353064663939,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+65366465656364636137653363376531,PS4 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+66613532303965383534396638613230,PS4 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
050000004c050000e60c0000fffe3f00,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
-050000004c050000e60c0000fffe3f80,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a3,rightx:a4,righty:a5,start:b16,x:b0,y:b2,platform:Android,
+050000004c050000e60c0000fffe3f80,PS5 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a3,rightx:a4,righty:a5,start:b16,x:b2,y:b17,platform:Android,
050000004c050000e60c0000ffff3f00,PS5 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-32346465346533616263386539323932,PS5 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-32633532643734376632656664383733,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
-37363764353731323963323639666565,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
-61303162353165316365336436343139,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
-64336263393933626535303339616332,Qanba 4RAF,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
-36626666353861663864336130363137,Razer Junglecat,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+32346465346533616263386539323932,PS5 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+32633532643734376632656664383733,PS5 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
+37363764353731323963323639666565,PS5 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
+61303162353165316365336436343139,PS5 Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
+64336263393933626535303339616332,Qanba 4RAF,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
+36626666353861663864336130363137,Razer Junglecat,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
05000000f8270000bf0b0000ffff3f00,Razer Kishi,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-62653861643333663663383332396665,Razer Kishi,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+62653861643333663663383332396665,Razer Kishi,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000003215000005070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000003215000007070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000003215000000090000bf7f3f00,Razer Serval,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,
-5a6869587520526574726f2042697420,Retro Bit Saturn Controller,a:b21,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b26,rightshoulder:b27,righttrigger:b28,start:b30,x:b23,y:b24,platform:Android,
+5a6869587520526574726f2042697420,Retro Bit Saturn Controller,a:b21,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b26,rightshoulder:b27,righttrigger:b28,start:b30,x:b23,y:b24,platform:Android,
32417865732031314b6579732047616d,Retro Bit SNES Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android,
36313938306539326233393732613361,Retro Bit SNES Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android,
-526574726f466c616720576972656420,Retro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,rightshoulder:b18,start:b10,x:b2,y:b3,platform:Android,
-61343739353764363165343237303336,Retro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,lefttrigger:b18,leftx:a0,lefty:a1,start:b10,x:b2,y:b3,platform:Android,
-526574726f696420506f636b65742043,Retroid Pocket,a:b1,b:b0,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
-582d426f7820436f6e74726f6c6c6572,Retroid Pocket,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-38653130373365613538333235303036,Retroid Pocket 2,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-64363363336633363736393038313463,Retrolink,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b6,platform:Android,
+526574726f466c616720576972656420,Retro Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b17,rightshoulder:b18,start:b10,x:b2,y:b3,platform:Android,
+61343739353764363165343237303336,Retro Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b17,lefttrigger:b18,leftx:a0,lefty:a1,start:b10,x:b2,y:b3,platform:Android,
+526574726f696420506f636b65742043,Retroid Pocket,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+582d426f7820436f6e74726f6c6c6572,Retroid Pocket,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38653130373365613538333235303036,Retroid Pocket 2,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+64363363336633363736393038313463,Retrolink,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,start:b6,platform:Android,
37393234373533633333323633646531,RetroUSB N64 RetroPort,+rightx:b17,+righty:b15,-rightx:b18,-righty:b6,a:b10,b:b9,dpdown:b19,dpleft:b1,dpright:b0,dpup:b2,leftshoulder:b7,lefttrigger:b20,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Android,
5365616c6965436f6d707574696e6720,RetroUSB N64 RetroPort,+rightx:b17,+righty:b15,-rightx:b18,-righty:b6,a:b10,b:b9,dpdown:b19,dpleft:b1,dpright:b0,dpup:b2,leftshoulder:b7,lefttrigger:b20,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Android,
526574726f5553422e636f6d20534e45,RetroUSB SNES RetroPort,a:b1,b:b20,back:b19,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b2,x:b0,y:b3,platform:Android,
64643037633038386238303966376137,RetroUSB SNES RetroPort,a:b1,b:b20,back:b19,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b2,x:b0,y:b3,platform:Android,
-37656564346533643138636436356230,Rock Candy Switch Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
-33373336396634316434323337666361,RumblePad 2,a:b22,b:b23,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b24,platform:Android,
-36363537303435333566386638366333,Samsung EIGP20,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-53616d73756e672047616d6520506164,Samsung EIGP20,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+37656564346533643138636436356230,Rock Candy Switch Controller,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+33373336396634316434323337666361,RumblePad 2,a:b22,b:b23,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b24,platform:Android,
+36363537303435333566386638366333,Samsung EIGP20,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+53616d73756e672047616d6520506164,Samsung EIGP20,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
66386565396238363534313863353065,Sanwa PlayOnline Mobile,a:b21,b:b22,back:b23,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b24,platform:Android,
-32383165316333383766336338373261,Saturn,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:a4,righttrigger:a5,x:b2,y:b3,platform:Android,
+32383165316333383766336338373261,Saturn,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:a4,righttrigger:a5,x:b2,y:b3,platform:Android,
38613865396530353338373763623431,Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,lefttrigger:b10,rightshoulder:b20,righttrigger:b19,start:b17,x:b2,y:b3,platform:Android,
-61316232336262373631343137633631,Saturn,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:a4,righttrigger:a5,x:b2,y:b3,platform:Android,
-30353835333338613130373363646337,SG H510,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
-66386262366536653765333235343634,SG H510,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,
-66633132393363353531373465633064,SG H510,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
-62653761636366393366613135366338,SN30 PP,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+61316232336262373631343137633631,Saturn,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:a4,righttrigger:a5,x:b2,y:b3,platform:Android,
+30353835333338613130373363646337,SG H510,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
+66386262366536653765333235343634,SG H510,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,
+66633132393363353531373465633064,SG H510,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
+62653761636366393366613135366338,SN30 PP,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
38376662666661636265313264613039,SNES,a:b0,b:b1,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android,
5346432f555342205061640000000000,SNES Adapter,a:b0,b:b1,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android,
-5553422047616d657061642000000000,SNES Controller,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
-63303964303462366136616266653561,Sony PSP,a:b21,b:b22,back:b27,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b28,x:b23,y:b24,platform:Android,
-63376637643462343766333462383235,Sony Vita,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a3,righty:a4,start:b18,x:b0,y:b2,platform:Android,
-476f6f676c65204c4c43205374616469,Stadia Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+5553422047616d657061642000000000,SNES Controller,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
+63303964303462366136616266653561,Sony PSP,a:b21,b:b22,back:b27,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b28,x:b23,y:b24,platform:Android,
+63376637643462343766333462383235,Sony Vita,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a3,righty:a4,start:b18,x:b0,y:b2,platform:Android,
+476f6f676c65204c4c43205374616469,Stadia Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
5374616469614e3848532d6532633400,Stadia Controller,a:b0,b:b1,back:b15,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android,
05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android,
-0500000011010000201400000f7e0f00,SteelSeries Nimbus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,x:b19,y:b2,platform:Android,
+0500000011010000201400000f7e0f00,SteelSeries Nimbus,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,x:b19,y:b2,platform:Android,
35306436396437373135383665646464,SteelSeries Nimbus Plus,a:b0,b:b1,leftshoulder:b3,leftstick:b17,lefttrigger:b9,leftx:a0,rightshoulder:b20,rightstick:b18,righttrigger:b10,rightx:a2,x:b19,y:b2,platform:Android,
33313930373536613937326534303931,Taito Egret II Mini Control Panel,a:b25,b:b23,back:b27,guide:b30,leftx:a0,lefty:a1,rightshoulder:b21,righttrigger:b22,start:b28,x:b29,y:b24,platform:Android,
-54475a20436f6e74726f6c6c65720000,TGZ Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-62363434353532386238336663643836,TGZ Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+54475a20436f6e74726f6c6c65720000,TGZ Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+62363434353532386238336663643836,TGZ Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
37323236633763666465316365313236,THEC64 Joystick,a:b21,b:b22,back:b27,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b27,x:b23,y:b24,platform:Android,
38346162326232346533316164363336,THEGamepad,a:b23,b:b22,back:b27,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b28,x:b24,y:b21,platform:Android,
050000004f0400000ed00000fffe3f00,ThrustMaster eSwap Pro Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-5477696e20555342204a6f7973746963,Twin Joystick,a:b22,b:b21,back:b28,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android,
-30623739343039643830333266346439,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-31643365666432386133346639383937,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-30386438313564306161393537333663,Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android,
-33333034646336346339646538643633,Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android,
+5477696e20555342204a6f7973746963,Twin Joystick,a:b22,b:b21,back:b28,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android,
+30623739343039643830333266346439,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+31643365666432386133346639383937,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+30386438313564306161393537333663,Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android,
+33333034646336346339646538643633,Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android,
050000005e0400008e02000000783f00,Xbox 360 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
30396232393162346330326334636566,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
38313038323730383864666463383533,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-58626f782033363020576972656c6573,Xbox 360 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+58626f782033363020576972656c6573,Xbox 360 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
65353331386662343338643939643636,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
65613532386633373963616462363038,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-47656e6572696320582d426f78207061,Xbox Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-4d6963726f736f667420582d426f7820,Xbox Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-64633436313965656664373634323364,Xbox Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+47656e6572696320582d426f78207061,Xbox Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+4d6963726f736f667420582d426f7820,Xbox Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+64633436313965656664373634323364,Xbox Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000005e04000091020000ff073f00,Xbox One Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
050000005e04000091020000ff073f80,Xbox One Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000005e040000e00200000ffe3f00,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android,
@@ -1985,11 +2034,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000e0020000ffff3f00,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b4,leftshoulder:b3,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android,
050000005e040000e0020000ffff3f80,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b4,leftshoulder:b3,leftstick:b8,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b10,x:b17,y:b2,platform:Android,
050000005e040000fd020000ffff3f00,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-33356661323266333733373865656366,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-34356136633366613530316338376136,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android,
-35623965373264386238353433656138,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+33356661323266333733373865656366,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+34356136633366613530316338376136,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android,
+35623965373264386238353433656138,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
36616131643361333337396261666433,Xbox One Controller,a:b0,b:b1,back:b15,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-58626f7820576972656c65737320436f,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+58626f7820576972656c65737320436f,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000005e040000000b000000783f00,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
050000005e040000000b000000783f80,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000005e040000050b0000ffff3f00,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
@@ -1998,8 +2047,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000fd020000ff7f3f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000005e040000120b000000783f00,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
050000005e040000120b000000783f80,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-050000005e040000130b0000ffff3f00,Xbox Series Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
-65633038363832353634653836396239,Xbox Series Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000005e040000130b0000ffff3f00,Xbox Series Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+65633038363832353634653836396239,Xbox Series Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000001727000044310000ffff3f00,XiaoMi Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,
# iOS
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 7e2227c729..a0c00d7716 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -236,7 +236,7 @@ void Input::get_argument_options(const StringName &p_function, int p_idx, List<S
continue;
}
- String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
+ String name = pi.name.substr(pi.name.find_char('/') + 1, pi.name.length());
r_options->push_back(name.quote());
}
}
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index d125bad252..045ac83cd8 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -35,6 +35,9 @@
#include "core/os/keyboard.h"
#include "core/os/os.h"
+const int InputEvent::DEVICE_ID_EMULATION = -1;
+const int InputEvent::DEVICE_ID_INTERNAL = -2;
+
void InputEvent::set_device(int p_device) {
device = p_device;
emit_changed();
@@ -1097,7 +1100,7 @@ JoyAxis InputEventJoypadMotion::get_axis() const {
void InputEventJoypadMotion::set_axis_value(float p_value) {
axis_value = p_value;
- pressed = Math::abs(axis_value) >= 0.5f;
+ pressed = Math::abs(axis_value) >= InputMap::DEFAULT_DEADZONE;
emit_changed();
}
diff --git a/core/input/input_event.h b/core/input/input_event.h
index 80bca28fbf..19176f748e 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -62,9 +62,8 @@ protected:
static void _bind_methods();
public:
- inline static constexpr int DEVICE_ID_EMULATION = -1;
- inline static constexpr int DEVICE_ID_INTERNAL = -2;
- inline static constexpr int DEVICE_ID_ALL_DEVICES = -3; // Signify that a given Action can be triggered by any device.
+ static const int DEVICE_ID_EMULATION;
+ static const int DEVICE_ID_INTERNAL;
void set_device(int p_device);
int get_device() const;
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index 6378f18545..abd2c80ce1 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -39,10 +39,12 @@
InputMap *InputMap::singleton = nullptr;
+int InputMap::ALL_DEVICES = -1;
+
void InputMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_action", "action"), &InputMap::has_action);
ClassDB::bind_method(D_METHOD("get_actions"), &InputMap::_get_actions);
- ClassDB::bind_method(D_METHOD("add_action", "action", "deadzone"), &InputMap::add_action, DEFVAL(0.2f));
+ ClassDB::bind_method(D_METHOD("add_action", "action", "deadzone"), &InputMap::add_action, DEFVAL(DEFAULT_DEADZONE));
ClassDB::bind_method(D_METHOD("erase_action", "action"), &InputMap::erase_action);
ClassDB::bind_method(D_METHOD("action_set_deadzone", "action", "deadzone"), &InputMap::action_set_deadzone);
@@ -104,7 +106,7 @@ void InputMap::get_argument_options(const StringName &p_function, int p_idx, Lis
continue;
}
- String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
+ String name = pi.name.substr(pi.name.find_char('/') + 1, pi.name.length());
r_options->push_back(name.quote());
}
}
@@ -161,7 +163,7 @@ List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Re
int i = 0;
for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) {
int device = E->get()->get_device();
- if (device == InputEvent::DEVICE_ID_ALL_DEVICES || device == p_event->get_device()) {
+ if (device == ALL_DEVICES || device == p_event->get_device()) {
if (E->get()->action_match(p_event, p_exact_match, p_action.deadzone, r_pressed, r_strength, r_raw_strength)) {
if (r_event_index) {
*r_event_index = i;
@@ -302,10 +304,10 @@ void InputMap::load_from_project_settings() {
continue;
}
- String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
+ String name = pi.name.substr(pi.name.find_char('/') + 1, pi.name.length());
Dictionary action = GLOBAL_GET(pi.name);
- float deadzone = action.has("deadzone") ? (float)action["deadzone"] : 0.2f;
+ float deadzone = action.has("deadzone") ? (float)action["deadzone"] : DEFAULT_DEADZONE;
Array events = action["events"];
add_action(name, deadzone);
diff --git a/core/input/input_map.h b/core/input/input_map.h
index 45798490f7..0479d45c57 100644
--- a/core/input/input_map.h
+++ b/core/input/input_map.h
@@ -43,12 +43,19 @@ class InputMap : public Object {
GDCLASS(InputMap, Object);
public:
+ /**
+ * A special value used to signify that a given Action can be triggered by any device
+ */
+ static int ALL_DEVICES;
+
struct Action {
int id;
float deadzone;
List<Ref<InputEvent>> inputs;
};
+ static constexpr float DEFAULT_DEADZONE = 0.2f;
+
private:
static InputMap *singleton;
@@ -74,7 +81,7 @@ public:
bool has_action(const StringName &p_action) const;
List<StringName> get_actions() const;
- void add_action(const StringName &p_action, float p_deadzone = 0.2);
+ void add_action(const StringName &p_action, float p_deadzone = DEFAULT_DEADZONE);
void erase_action(const StringName &p_action);
float action_get_deadzone(const StringName &p_action);
diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp
index 5d2f65ca99..14588923cb 100644
--- a/core/io/dir_access.cpp
+++ b/core/io/dir_access.cpp
@@ -155,9 +155,9 @@ Error DirAccess::make_dir_recursive(const String &p_dir) {
} else if (full_dir.begins_with("user://")) {
base = "user://";
} else if (full_dir.is_network_share_path()) {
- int pos = full_dir.find("/", 2);
+ int pos = full_dir.find_char('/', 2);
ERR_FAIL_COND_V(pos < 0, ERR_INVALID_PARAMETER);
- pos = full_dir.find("/", pos + 1);
+ pos = full_dir.find_char('/', pos + 1);
ERR_FAIL_COND_V(pos < 0, ERR_INVALID_PARAMETER);
base = full_dir.substr(0, pos + 1);
} else if (full_dir.begins_with("/")) {
diff --git a/modules/text_server_adv/thorvg_bounds_iterator.h b/core/io/file_access.compat.inc
index afa2c13764..ed16050126 100644
--- a/modules/text_server_adv/thorvg_bounds_iterator.h
+++ b/core/io/file_access.compat.inc
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* thorvg_bounds_iterator.h */
+/* file_access.compat.inc */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,31 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifndef THORVG_BOUNDS_ITERATOR_H
-#define THORVG_BOUNDS_ITERATOR_H
+#ifndef DISABLE_DEPRECATED
-#ifdef GDEXTENSION
-// Headers for building as GDExtension plug-in.
+Ref<FileAccess> FileAccess::_open_encrypted_bind_compat_98918(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) {
+ return open_encrypted(p_path, p_mode_flags, p_key, Vector<uint8_t>());
+}
-#include <godot_cpp/core/mutex_lock.hpp>
-#include <godot_cpp/godot.hpp>
+void FileAccess::_bind_compatibility_methods() {
+ ClassDB::bind_compatibility_static_method("FileAccess", D_METHOD("open_encrypted", "path", "mode_flags", "key"), &FileAccess::_open_encrypted_bind_compat_98918);
+}
-using namespace godot;
-
-#elif defined(GODOT_MODULE)
-// Headers for building as built-in module.
-
-#include "core/typedefs.h"
-
-#include "modules/modules_enabled.gen.h" // For svg.
-#endif
-
-#ifdef MODULE_SVG_ENABLED
-
-#include <thorvg.h>
-
-void tvg_get_bounds(tvg::Picture *p_picture, float &r_min_x, float &r_min_y, float &r_max_x, float &r_max_y);
-
-#endif // MODULE_SVG_ENABLED
-
-#endif // THORVG_BOUNDS_ITERATOR_H
+#endif // DISABLE_DEPRECATED
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index d8bf645a7d..29027cade1 100644
--- a/core/io/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "file_access.h"
+#include "file_access.compat.inc"
#include "core/config/project_settings.h"
#include "core/crypto/crypto_core.h"
@@ -70,7 +71,7 @@ void FileAccess::_set_access_type(AccessType p_access) {
Ref<FileAccess> FileAccess::create_for_path(const String &p_path) {
Ref<FileAccess> ret;
- if (p_path.begins_with("res://")) {
+ if (p_path.begins_with("res://") || p_path.begins_with("uid://")) {
ret = create(ACCESS_RESOURCES);
} else if (p_path.begins_with("user://")) {
ret = create(ACCESS_USERDATA);
@@ -124,7 +125,7 @@ Ref<FileAccess> FileAccess::_open(const String &p_path, ModeFlags p_mode_flags)
return fa;
}
-Ref<FileAccess> FileAccess::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) {
+Ref<FileAccess> FileAccess::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key, const Vector<uint8_t> &p_iv) {
Ref<FileAccess> fa = _open(p_path, p_mode_flags);
if (fa.is_null()) {
return fa;
@@ -132,7 +133,7 @@ Ref<FileAccess> FileAccess::open_encrypted(const String &p_path, ModeFlags p_mod
Ref<FileAccessEncrypted> fae;
fae.instantiate();
- Error err = fae->open_and_parse(fa, p_key, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
+ Error err = fae->open_and_parse(fa, p_key, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ, true, p_iv);
last_file_open_error = err;
if (err) {
return Ref<FileAccess>();
@@ -182,13 +183,17 @@ FileAccess::AccessType FileAccess::get_access_type() const {
}
String FileAccess::fix_path(const String &p_path) const {
- //helper used by file accesses that use a single filesystem
+ // Helper used by file accesses that use a single filesystem.
String r_path = p_path.replace("\\", "/");
switch (_access_type) {
case ACCESS_RESOURCES: {
if (ProjectSettings::get_singleton()) {
+ if (r_path.begins_with("uid://")) {
+ r_path = ResourceUID::uid_to_path(r_path);
+ }
+
if (r_path.begins_with("res://")) {
String resource_path = ProjectSettings::get_singleton()->get_resource_path();
if (!resource_path.is_empty()) {
@@ -263,6 +268,10 @@ uint64_t FileAccess::get_64() const {
return data;
}
+float FileAccess::get_half() const {
+ return Math::half_to_float(get_16());
+}
+
float FileAccess::get_float() const {
MarshallFloat m;
m.i = get_32();
@@ -522,6 +531,10 @@ void FileAccess::store_real(real_t p_real) {
}
}
+void FileAccess::store_half(float p_dest) {
+ store_16(Math::make_half_float(p_dest));
+}
+
void FileAccess::store_float(float p_dest) {
MarshallFloat m;
m.f = p_dest;
@@ -806,7 +819,7 @@ String FileAccess::get_sha256(const String &p_file) {
void FileAccess::_bind_methods() {
ClassDB::bind_static_method("FileAccess", D_METHOD("open", "path", "flags"), &FileAccess::_open);
- ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted", "path", "mode_flags", "key"), &FileAccess::open_encrypted);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted", "path", "mode_flags", "key", "iv"), &FileAccess::open_encrypted, DEFVAL(Vector<uint8_t>()));
ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted_with_pass", "path", "mode_flags", "pass"), &FileAccess::open_encrypted_pass);
ClassDB::bind_static_method("FileAccess", D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &FileAccess::open_compressed, DEFVAL(0));
ClassDB::bind_static_method("FileAccess", D_METHOD("get_open_error"), &FileAccess::get_open_error);
@@ -828,6 +841,7 @@ void FileAccess::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_16"), &FileAccess::get_16);
ClassDB::bind_method(D_METHOD("get_32"), &FileAccess::get_32);
ClassDB::bind_method(D_METHOD("get_64"), &FileAccess::get_64);
+ ClassDB::bind_method(D_METHOD("get_half"), &FileAccess::get_half);
ClassDB::bind_method(D_METHOD("get_float"), &FileAccess::get_float);
ClassDB::bind_method(D_METHOD("get_double"), &FileAccess::get_double);
ClassDB::bind_method(D_METHOD("get_real"), &FileAccess::get_real);
@@ -846,6 +860,7 @@ void FileAccess::_bind_methods() {
ClassDB::bind_method(D_METHOD("store_16", "value"), &FileAccess::store_16);
ClassDB::bind_method(D_METHOD("store_32", "value"), &FileAccess::store_32);
ClassDB::bind_method(D_METHOD("store_64", "value"), &FileAccess::store_64);
+ ClassDB::bind_method(D_METHOD("store_half", "value"), &FileAccess::store_half);
ClassDB::bind_method(D_METHOD("store_float", "value"), &FileAccess::store_float);
ClassDB::bind_method(D_METHOD("store_double", "value"), &FileAccess::store_double);
ClassDB::bind_method(D_METHOD("store_real", "value"), &FileAccess::store_real);
diff --git a/core/io/file_access.h b/core/io/file_access.h
index 7f5687fe03..48984c6c1b 100644
--- a/core/io/file_access.h
+++ b/core/io/file_access.h
@@ -109,6 +109,12 @@ protected:
static FileCloseFailNotify close_fail_notify;
+#ifndef DISABLE_DEPRECATED
+ static Ref<FileAccess> _open_encrypted_bind_compat_98918(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key);
+
+ static void _bind_compatibility_methods();
+#endif
+
private:
static bool backup_save;
thread_local static Error last_file_open_error;
@@ -142,6 +148,7 @@ public:
virtual uint32_t get_32() const; ///< get 32 bits uint
virtual uint64_t get_64() const; ///< get 64 bits uint
+ virtual float get_half() const;
virtual float get_float() const;
virtual double get_double() const;
virtual real_t get_real() const;
@@ -173,6 +180,7 @@ public:
virtual void store_32(uint32_t p_dest); ///< store 32 bits uint
virtual void store_64(uint64_t p_dest); ///< store 64 bits uint
+ virtual void store_half(float p_dest);
virtual void store_float(float p_dest);
virtual void store_double(double p_dest);
virtual void store_real(real_t p_real);
@@ -199,7 +207,7 @@ public:
static Ref<FileAccess> create_for_path(const String &p_path);
static Ref<FileAccess> open(const String &p_path, int p_mode_flags, Error *r_error = nullptr); /// Create a file access (for the current platform) this is the only portable way of accessing files.
- static Ref<FileAccess> open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key);
+ static Ref<FileAccess> open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key, const Vector<uint8_t> &p_iv = Vector<uint8_t>());
static Ref<FileAccess> open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass);
static Ref<FileAccess> open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ);
static Error get_open_error();
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index 24be9ef230..ba26f2e07b 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -36,7 +36,7 @@
#include <stdio.h>
-Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic) {
+Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic, const Vector<uint8_t> &p_iv) {
ERR_FAIL_COND_V_MSG(file.is_valid(), ERR_ALREADY_IN_USE, vformat("Can't open file while another file from path '%s' is open.", file->get_path_absolute()));
ERR_FAIL_COND_V(p_key.size() != 32, ERR_INVALID_PARAMETER);
@@ -49,6 +49,16 @@ Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<u
writing = true;
file = p_base;
key = p_key;
+ if (p_iv.is_empty()) {
+ iv.resize(16);
+ CryptoCore::RandomGenerator rng;
+ ERR_FAIL_COND_V_MSG(rng.init(), FAILED, "Failed to initialize random number generator.");
+ Error err = rng.get_random_bytes(iv.ptrw(), 16);
+ ERR_FAIL_COND_V(err != OK, err);
+ } else {
+ ERR_FAIL_COND_V(p_iv.size() != 16, ERR_INVALID_PARAMETER);
+ iv = p_iv;
+ }
} else if (p_mode == MODE_READ) {
writing = false;
@@ -63,10 +73,8 @@ Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<u
p_base->get_buffer(md5d, 16);
length = p_base->get_64();
- unsigned char iv[16];
- for (int i = 0; i < 16; i++) {
- iv[i] = p_base->get_8();
- }
+ iv.resize(16);
+ p_base->get_buffer(iv.ptrw(), 16);
base = p_base->get_position();
ERR_FAIL_COND_V(p_base->get_length() < base + length, ERR_FILE_CORRUPT);
@@ -83,7 +91,7 @@ Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<u
CryptoCore::AESContext ctx;
ctx.set_encode_key(key.ptrw(), 256); // Due to the nature of CFB, same key schedule is used for both encryption and decryption!
- ctx.decrypt_cfb(ds, iv, data.ptrw(), data.ptrw());
+ ctx.decrypt_cfb(ds, iv.ptrw(), data.ptrw(), data.ptrw());
}
data.resize(length);
@@ -145,14 +153,9 @@ void FileAccessEncrypted::_close() {
file->store_buffer(hash, 16);
file->store_64(data.size());
+ file->store_buffer(iv.ptr(), 16);
- unsigned char iv[16];
- for (int i = 0; i < 16; i++) {
- iv[i] = Math::rand() % 256;
- file->store_8(iv[i]);
- }
-
- ctx.encrypt_cfb(len, iv, compressed.ptrw(), compressed.ptrw());
+ ctx.encrypt_cfb(len, iv.ptrw(), compressed.ptrw(), compressed.ptrw());
file->store_buffer(compressed.ptr(), compressed.size());
data.clear();
diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h
index 5f8c803d60..63a8cab145 100644
--- a/core/io/file_access_encrypted.h
+++ b/core/io/file_access_encrypted.h
@@ -44,6 +44,7 @@ public:
};
private:
+ Vector<uint8_t> iv;
Vector<uint8_t> key;
bool writing = false;
Ref<FileAccess> file;
@@ -57,9 +58,11 @@ private:
void _close();
public:
- Error open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true);
+ Error open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true, const Vector<uint8_t> &p_iv = Vector<uint8_t>());
Error open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode);
+ Vector<uint8_t> get_iv() const { return iv; }
+
virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index b9af1bfb57..8b6b445cea 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -590,8 +590,6 @@ String DirAccessPack::get_current_dir(bool p_include_drive) const {
}
bool DirAccessPack::file_exists(String p_file) {
- p_file = fix_path(p_file);
-
PackedData::PackedDir *pd = _find_dir(p_file.get_base_dir());
if (!pd) {
return false;
@@ -600,8 +598,6 @@ bool DirAccessPack::file_exists(String p_file) {
}
bool DirAccessPack::dir_exists(String p_dir) {
- p_dir = fix_path(p_dir);
-
return _find_dir(p_dir) != nullptr;
}
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index bf44b3a2db..b957a43de2 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -205,7 +205,7 @@ Ref<FileAccess> PackedData::try_open_path(const String &p_path) {
}
bool PackedData::has_path(const String &p_path) {
- return files.has(PathMD5(p_path.simplify_path().md5_buffer()));
+ return files.has(PathMD5(p_path.simplify_path().trim_prefix("res://").md5_buffer()));
}
bool PackedData::has_directory(const String &p_path) {
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
index 9e426c4908..b7a324e710 100644
--- a/core/io/http_client.cpp
+++ b/core/io/http_client.cpp
@@ -101,7 +101,7 @@ Error HTTPClient::verify_headers(const Vector<String> &p_headers) {
for (int i = 0; i < p_headers.size(); i++) {
String sanitized = p_headers[i].strip_edges();
ERR_FAIL_COND_V_MSG(sanitized.is_empty(), ERR_INVALID_PARAMETER, vformat("Invalid HTTP header at index %d: empty.", i));
- ERR_FAIL_COND_V_MSG(sanitized.find(":") < 1, ERR_INVALID_PARAMETER,
+ ERR_FAIL_COND_V_MSG(sanitized.find_char(':') < 1, ERR_INVALID_PARAMETER,
vformat("Invalid HTTP header at index %d: String must contain header-value pair, delimited by ':', but was: '%s'.", i, p_headers[i]));
}
@@ -113,7 +113,7 @@ Dictionary HTTPClient::_get_response_headers_as_dictionary() {
get_response_headers(&rh);
Dictionary ret;
for (const String &s : rh) {
- int sp = s.find(":");
+ int sp = s.find_char(':');
if (sp == -1) {
continue;
}
diff --git a/core/io/http_client_tcp.cpp b/core/io/http_client_tcp.cpp
index 237ba30a80..1382aecb38 100644
--- a/core/io/http_client_tcp.cpp
+++ b/core/io/http_client_tcp.cpp
@@ -508,11 +508,11 @@ Error HTTPClientTCP::poll() {
continue;
}
if (s.begins_with("content-length:")) {
- body_size = s.substr(s.find(":") + 1, s.length()).strip_edges().to_int();
+ body_size = s.substr(s.find_char(':') + 1, s.length()).strip_edges().to_int();
body_left = body_size;
} else if (s.begins_with("transfer-encoding:")) {
- String encoding = header.substr(header.find(":") + 1, header.length()).strip_edges();
+ String encoding = header.substr(header.find_char(':') + 1, header.length()).strip_edges();
if (encoding == "chunked") {
chunked = true;
}
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 9b5bb058ef..128bbf3e6f 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -44,24 +44,24 @@
#include <cmath>
const char *Image::format_names[Image::FORMAT_MAX] = {
- "Lum8", //luminance
- "LumAlpha8", //luminance-alpha
+ "Lum8",
+ "LumAlpha8",
"Red8",
"RedGreen",
"RGB8",
"RGBA8",
"RGBA4444",
- "RGBA5551",
- "RFloat", //float
+ "RGBA5551", // Actually RGB565, kept as RGBA5551 for compatibility.
+ "RFloat",
"RGFloat",
"RGBFloat",
"RGBAFloat",
- "RHalf", //half float
+ "RHalf",
"RGHalf",
"RGBHalf",
"RGBAHalf",
"RGBE9995",
- "DXT1 RGB8", //s3tc
+ "DXT1 RGB8",
"DXT3 RGBA8",
"DXT5 RGBA8",
"RGTC Red8",
@@ -69,9 +69,9 @@ const char *Image::format_names[Image::FORMAT_MAX] = {
"BPTC_RGBA",
"BPTC_RGBF",
"BPTC_RGBFU",
- "ETC", //etc1
- "ETC2_R11", //etc2
- "ETC2_R11S", //signed", NOT srgb.
+ "ETC",
+ "ETC2_R11",
+ "ETC2_R11S",
"ETC2_RG11",
"ETC2_RG11S",
"ETC2_RGB8",
@@ -85,17 +85,60 @@ const char *Image::format_names[Image::FORMAT_MAX] = {
"ASTC_8x8_HDR",
};
+// External saver function pointers.
+
SavePNGFunc Image::save_png_func = nullptr;
SaveJPGFunc Image::save_jpg_func = nullptr;
SaveEXRFunc Image::save_exr_func = nullptr;
+SaveWebPFunc Image::save_webp_func = nullptr;
SavePNGBufferFunc Image::save_png_buffer_func = nullptr;
-SaveEXRBufferFunc Image::save_exr_buffer_func = nullptr;
SaveJPGBufferFunc Image::save_jpg_buffer_func = nullptr;
-
-SaveWebPFunc Image::save_webp_func = nullptr;
+SaveEXRBufferFunc Image::save_exr_buffer_func = nullptr;
SaveWebPBufferFunc Image::save_webp_buffer_func = nullptr;
+// External loader function pointers.
+
+ImageMemLoadFunc Image::_png_mem_loader_func = nullptr;
+ImageMemLoadFunc Image::_png_mem_unpacker_func = nullptr;
+ImageMemLoadFunc Image::_jpg_mem_loader_func = nullptr;
+ImageMemLoadFunc Image::_webp_mem_loader_func = nullptr;
+ImageMemLoadFunc Image::_tga_mem_loader_func = nullptr;
+ImageMemLoadFunc Image::_bmp_mem_loader_func = nullptr;
+ScalableImageMemLoadFunc Image::_svg_scalable_mem_loader_func = nullptr;
+ImageMemLoadFunc Image::_ktx_mem_loader_func = nullptr;
+
+// External VRAM compression function pointers.
+
+void (*Image::_image_compress_bc_func)(Image *, Image::UsedChannels) = nullptr;
+void (*Image::_image_compress_bptc_func)(Image *, Image::UsedChannels) = nullptr;
+void (*Image::_image_compress_etc1_func)(Image *) = nullptr;
+void (*Image::_image_compress_etc2_func)(Image *, Image::UsedChannels) = nullptr;
+void (*Image::_image_compress_astc_func)(Image *, Image::ASTCFormat) = nullptr;
+
+Error (*Image::_image_compress_bptc_rd_func)(Image *, Image::UsedChannels) = nullptr;
+Error (*Image::_image_compress_bc_rd_func)(Image *, Image::UsedChannels) = nullptr;
+
+// External VRAM decompression function pointers.
+
+void (*Image::_image_decompress_bc)(Image *) = nullptr;
+void (*Image::_image_decompress_bptc)(Image *) = nullptr;
+void (*Image::_image_decompress_etc1)(Image *) = nullptr;
+void (*Image::_image_decompress_etc2)(Image *) = nullptr;
+void (*Image::_image_decompress_astc)(Image *) = nullptr;
+
+// External packer function pointers.
+
+Vector<uint8_t> (*Image::webp_lossy_packer)(const Ref<Image> &, float) = nullptr;
+Vector<uint8_t> (*Image::webp_lossless_packer)(const Ref<Image> &) = nullptr;
+Vector<uint8_t> (*Image::png_packer)(const Ref<Image> &) = nullptr;
+Vector<uint8_t> (*Image::basis_universal_packer)(const Ref<Image> &, Image::UsedChannels) = nullptr;
+
+Ref<Image> (*Image::webp_unpacker)(const Vector<uint8_t> &) = nullptr;
+Ref<Image> (*Image::png_unpacker)(const Vector<uint8_t> &) = nullptr;
+Ref<Image> (*Image::basis_universal_unpacker)(const Vector<uint8_t> &) = nullptr;
+Ref<Image> (*Image::basis_universal_unpacker_ptr)(const uint8_t *, int) = nullptr;
+
void Image::_put_pixelb(int p_x, int p_y, uint32_t p_pixel_size, uint8_t *p_data, const uint8_t *p_pixel) {
uint32_t ofs = (p_y * width + p_x) * p_pixel_size;
memcpy(p_data + ofs, p_pixel, p_pixel_size);
@@ -109,9 +152,9 @@ void Image::_get_pixelb(int p_x, int p_y, uint32_t p_pixel_size, const uint8_t *
int Image::get_format_pixel_size(Format p_format) {
switch (p_format) {
case FORMAT_L8:
- return 1; //luminance
+ return 1;
case FORMAT_LA8:
- return 2; //luminance-alpha
+ return 2;
case FORMAT_R8:
return 1;
case FORMAT_RG8:
@@ -125,7 +168,7 @@ int Image::get_format_pixel_size(Format p_format) {
case FORMAT_RGB565:
return 2;
case FORMAT_RF:
- return 4; //float
+ return 4;
case FORMAT_RGF:
return 8;
case FORMAT_RGBF:
@@ -133,7 +176,7 @@ int Image::get_format_pixel_size(Format p_format) {
case FORMAT_RGBAF:
return 16;
case FORMAT_RH:
- return 2; //half float
+ return 2;
case FORMAT_RGH:
return 4;
case FORMAT_RGBH:
@@ -143,27 +186,27 @@ int Image::get_format_pixel_size(Format p_format) {
case FORMAT_RGBE9995:
return 4;
case FORMAT_DXT1:
- return 1; //s3tc bc1
+ return 1;
case FORMAT_DXT3:
- return 1; //bc2
+ return 1;
case FORMAT_DXT5:
- return 1; //bc3
+ return 1;
case FORMAT_RGTC_R:
- return 1; //bc4
+ return 1;
case FORMAT_RGTC_RG:
- return 1; //bc5
+ return 1;
case FORMAT_BPTC_RGBA:
- return 1; //btpc bc6h
+ return 1;
case FORMAT_BPTC_RGBF:
- return 1; //float /
+ return 1;
case FORMAT_BPTC_RGBFU:
- return 1; //unsigned float
+ return 1;
case FORMAT_ETC:
- return 1; //etc1
+ return 1;
case FORMAT_ETC2_R11:
- return 1; //etc2
+ return 1;
case FORMAT_ETC2_R11S:
- return 1; //signed: return 1; NOT srgb.
+ return 1;
case FORMAT_ETC2_RG11:
return 1;
case FORMAT_ETC2_RG11S:
@@ -194,12 +237,11 @@ int Image::get_format_pixel_size(Format p_format) {
void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) {
switch (p_format) {
- case FORMAT_DXT1: //s3tc bc1
- case FORMAT_DXT3: //bc2
- case FORMAT_DXT5: //bc3
- case FORMAT_RGTC_R: //bc4
- case FORMAT_RGTC_RG: { //bc5 case case FORMAT_DXT1:
-
+ case FORMAT_DXT1:
+ case FORMAT_DXT3:
+ case FORMAT_DXT5:
+ case FORMAT_RGTC_R:
+ case FORMAT_RGTC_RG: {
r_w = 4;
r_h = 4;
} break;
@@ -213,8 +255,8 @@ void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) {
r_w = 4;
r_h = 4;
} break;
- case FORMAT_ETC2_R11: //etc2
- case FORMAT_ETC2_R11S: //signed: NOT srgb.
+ case FORMAT_ETC2_R11:
+ case FORMAT_ETC2_R11S:
case FORMAT_ETC2_RG11:
case FORMAT_ETC2_RG11S:
case FORMAT_ETC2_RGB8:
@@ -224,19 +266,16 @@ void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) {
case FORMAT_DXT5_RA_AS_RG: {
r_w = 4;
r_h = 4;
-
} break;
case FORMAT_ASTC_4x4:
case FORMAT_ASTC_4x4_HDR: {
r_w = 4;
r_h = 4;
-
} break;
case FORMAT_ASTC_8x8:
case FORMAT_ASTC_8x8_HDR: {
r_w = 8;
r_h = 8;
-
} break;
default: {
r_w = 1;
@@ -257,12 +296,11 @@ int Image::get_format_pixel_rshift(Format p_format) {
int Image::get_format_block_size(Format p_format) {
switch (p_format) {
- case FORMAT_DXT1: //s3tc bc1
- case FORMAT_DXT3: //bc2
- case FORMAT_DXT5: //bc3
- case FORMAT_RGTC_R: //bc4
- case FORMAT_RGTC_RG: { //bc5 case case FORMAT_DXT1:
-
+ case FORMAT_DXT1:
+ case FORMAT_DXT3:
+ case FORMAT_DXT5:
+ case FORMAT_RGTC_R:
+ case FORMAT_RGTC_RG: {
return 4;
}
case FORMAT_ETC: {
@@ -273,17 +311,15 @@ int Image::get_format_block_size(Format p_format) {
case FORMAT_BPTC_RGBFU: {
return 4;
}
- case FORMAT_ETC2_R11: //etc2
- case FORMAT_ETC2_R11S: //signed: NOT srgb.
+ case FORMAT_ETC2_R11:
+ case FORMAT_ETC2_R11S:
case FORMAT_ETC2_RG11:
case FORMAT_ETC2_RG11S:
case FORMAT_ETC2_RGB8:
case FORMAT_ETC2_RGBA8:
case FORMAT_ETC2_RGB8A1:
- case FORMAT_ETC2_RA_AS_RG: //used to make basis universal happy
- case FORMAT_DXT5_RA_AS_RG: //used to make basis universal happy
-
- {
+ case FORMAT_ETC2_RA_AS_RG:
+ case FORMAT_DXT5_RA_AS_RG: {
return 4;
}
case FORMAT_ASTC_4x4:
@@ -459,7 +495,7 @@ int Image::get_mipmap_count() const {
}
}
-//using template generates perfectly optimized code due to constant expression reduction and unused variable removal present in all compilers
+// Using template generates perfectly optimized code due to constant expression reduction and unused variable removal present in all compilers.
template <uint32_t read_bytes, bool read_alpha, uint32_t write_bytes, bool write_alpha, bool read_gray, bool write_gray>
static void _convert(int p_width, int p_height, const uint8_t *p_src, uint8_t *p_dst) {
constexpr uint32_t max_bytes = MAX(read_bytes, write_bytes);
@@ -551,7 +587,7 @@ void Image::convert(Format p_new_format) {
ERR_FAIL_MSG("Cannot convert to <-> from compressed formats. Use compress() and decompress() instead.");
} else if (!_are_formats_compatible(format, p_new_format)) {
- //use put/set pixel which is slower but works with non byte formats
+ // Use put/set pixel which is slower but works with non-byte formats.
Image new_img(width, height, mipmaps, p_new_format);
for (int mip = 0; mip < mipmap_count; mip++) {
@@ -1694,7 +1730,7 @@ void Image::flip_x() {
}
}
-/// Get mipmap size and offset.
+// Get mipmap size and offset.
int64_t Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps, int *r_mm_width, int *r_mm_height) {
// Data offset in mipmaps (including the original texture).
int64_t size = 0;
@@ -2575,23 +2611,25 @@ Image::AlphaMode Image::detect_alpha() const {
}
Error Image::load(const String &p_path) {
+ String path = ResourceUID::ensure_path(p_path);
#ifdef DEBUG_ENABLED
- if (p_path.begins_with("res://") && ResourceLoader::exists(p_path)) {
- WARN_PRINT(vformat("Loaded resource as image file, this will not work on export: '%s'. Instead, import the image file as an Image resource and load it normally as a resource.", p_path));
+ if (path.begins_with("res://") && ResourceLoader::exists(path)) {
+ WARN_PRINT(vformat("Loaded resource as image file, this will not work on export: '%s'. Instead, import the image file as an Image resource and load it normally as a resource.", path));
}
#endif
- return ImageLoader::load_image(p_path, this);
+ return ImageLoader::load_image(path, this);
}
Ref<Image> Image::load_from_file(const String &p_path) {
+ String path = ResourceUID::ensure_path(p_path);
#ifdef DEBUG_ENABLED
- if (p_path.begins_with("res://") && ResourceLoader::exists(p_path)) {
- WARN_PRINT(vformat("Loaded resource as image file, this will not work on export: '%s'. Instead, import the image file as an Image resource and load it normally as a resource.", p_path));
+ if (path.begins_with("res://") && ResourceLoader::exists(path)) {
+ WARN_PRINT(vformat("Loaded resource as image file, this will not work on export: '%s'. Instead, import the image file as an Image resource and load it normally as a resource.", path));
}
#endif
Ref<Image> image;
image.instantiate();
- Error err = ImageLoader::load_image(p_path, image);
+ Error err = ImageLoader::load_image(path, image);
if (err != OK) {
ERR_FAIL_V_MSG(Ref<Image>(), vformat("Failed to load image. Error %d", err));
}
@@ -3134,37 +3172,6 @@ void Image::fill_rect(const Rect2i &p_rect, const Color &p_color) {
}
}
-ImageMemLoadFunc Image::_png_mem_loader_func = nullptr;
-ImageMemLoadFunc Image::_png_mem_unpacker_func = nullptr;
-ImageMemLoadFunc Image::_jpg_mem_loader_func = nullptr;
-ImageMemLoadFunc Image::_webp_mem_loader_func = nullptr;
-ImageMemLoadFunc Image::_tga_mem_loader_func = nullptr;
-ImageMemLoadFunc Image::_bmp_mem_loader_func = nullptr;
-ScalableImageMemLoadFunc Image::_svg_scalable_mem_loader_func = nullptr;
-ImageMemLoadFunc Image::_ktx_mem_loader_func = nullptr;
-
-void (*Image::_image_compress_bc_func)(Image *, Image::UsedChannels) = nullptr;
-void (*Image::_image_compress_bptc_func)(Image *, Image::UsedChannels) = nullptr;
-void (*Image::_image_compress_etc1_func)(Image *) = nullptr;
-void (*Image::_image_compress_etc2_func)(Image *, Image::UsedChannels) = nullptr;
-void (*Image::_image_compress_astc_func)(Image *, Image::ASTCFormat) = nullptr;
-Error (*Image::_image_compress_bptc_rd_func)(Image *, Image::UsedChannels) = nullptr;
-Error (*Image::_image_compress_bc_rd_func)(Image *, Image::UsedChannels) = nullptr;
-void (*Image::_image_decompress_bc)(Image *) = nullptr;
-void (*Image::_image_decompress_bptc)(Image *) = nullptr;
-void (*Image::_image_decompress_etc1)(Image *) = nullptr;
-void (*Image::_image_decompress_etc2)(Image *) = nullptr;
-void (*Image::_image_decompress_astc)(Image *) = nullptr;
-
-Vector<uint8_t> (*Image::webp_lossy_packer)(const Ref<Image> &, float) = nullptr;
-Vector<uint8_t> (*Image::webp_lossless_packer)(const Ref<Image> &) = nullptr;
-Ref<Image> (*Image::webp_unpacker)(const Vector<uint8_t> &) = nullptr;
-Vector<uint8_t> (*Image::png_packer)(const Ref<Image> &) = nullptr;
-Ref<Image> (*Image::png_unpacker)(const Vector<uint8_t> &) = nullptr;
-Vector<uint8_t> (*Image::basis_universal_packer)(const Ref<Image> &, Image::UsedChannels) = nullptr;
-Ref<Image> (*Image::basis_universal_unpacker)(const Vector<uint8_t> &) = nullptr;
-Ref<Image> (*Image::basis_universal_unpacker_ptr)(const uint8_t *, int) = nullptr;
-
void Image::_set_data(const Dictionary &p_data) {
ERR_FAIL_COND(!p_data.has("width"));
ERR_FAIL_COND(!p_data.has("height"));
@@ -3204,6 +3211,14 @@ Color Image::get_pixelv(const Point2i &p_point) const {
return get_pixel(p_point.x, p_point.y);
}
+void Image::_copy_internals_from(const Image &p_image) {
+ format = p_image.format;
+ width = p_image.width;
+ height = p_image.height;
+ mipmaps = p_image.mipmaps;
+ data = p_image.data;
+}
+
Color Image::_get_color_at_ofs(const uint8_t *ptr, uint32_t ofs) const {
switch (format) {
case FORMAT_L8: {
@@ -3643,34 +3658,34 @@ void Image::_bind_methods() {
BIND_CONSTANT(MAX_WIDTH);
BIND_CONSTANT(MAX_HEIGHT);
- BIND_ENUM_CONSTANT(FORMAT_L8); //luminance
- BIND_ENUM_CONSTANT(FORMAT_LA8); //luminance-alpha
+ BIND_ENUM_CONSTANT(FORMAT_L8);
+ BIND_ENUM_CONSTANT(FORMAT_LA8);
BIND_ENUM_CONSTANT(FORMAT_R8);
BIND_ENUM_CONSTANT(FORMAT_RG8);
BIND_ENUM_CONSTANT(FORMAT_RGB8);
BIND_ENUM_CONSTANT(FORMAT_RGBA8);
BIND_ENUM_CONSTANT(FORMAT_RGBA4444);
BIND_ENUM_CONSTANT(FORMAT_RGB565);
- BIND_ENUM_CONSTANT(FORMAT_RF); //float
+ BIND_ENUM_CONSTANT(FORMAT_RF);
BIND_ENUM_CONSTANT(FORMAT_RGF);
BIND_ENUM_CONSTANT(FORMAT_RGBF);
BIND_ENUM_CONSTANT(FORMAT_RGBAF);
- BIND_ENUM_CONSTANT(FORMAT_RH); //half float
+ BIND_ENUM_CONSTANT(FORMAT_RH);
BIND_ENUM_CONSTANT(FORMAT_RGH);
BIND_ENUM_CONSTANT(FORMAT_RGBH);
BIND_ENUM_CONSTANT(FORMAT_RGBAH);
BIND_ENUM_CONSTANT(FORMAT_RGBE9995);
- BIND_ENUM_CONSTANT(FORMAT_DXT1); //s3tc bc1
- BIND_ENUM_CONSTANT(FORMAT_DXT3); //bc2
- BIND_ENUM_CONSTANT(FORMAT_DXT5); //bc3
+ BIND_ENUM_CONSTANT(FORMAT_DXT1);
+ BIND_ENUM_CONSTANT(FORMAT_DXT3);
+ BIND_ENUM_CONSTANT(FORMAT_DXT5);
BIND_ENUM_CONSTANT(FORMAT_RGTC_R);
BIND_ENUM_CONSTANT(FORMAT_RGTC_RG);
- BIND_ENUM_CONSTANT(FORMAT_BPTC_RGBA); //btpc bc6h
- BIND_ENUM_CONSTANT(FORMAT_BPTC_RGBF); //float /
- BIND_ENUM_CONSTANT(FORMAT_BPTC_RGBFU); //unsigned float
- BIND_ENUM_CONSTANT(FORMAT_ETC); //etc1
- BIND_ENUM_CONSTANT(FORMAT_ETC2_R11); //etc2
- BIND_ENUM_CONSTANT(FORMAT_ETC2_R11S); //signed ); NOT srgb.
+ BIND_ENUM_CONSTANT(FORMAT_BPTC_RGBA);
+ BIND_ENUM_CONSTANT(FORMAT_BPTC_RGBF);
+ BIND_ENUM_CONSTANT(FORMAT_BPTC_RGBFU);
+ BIND_ENUM_CONSTANT(FORMAT_ETC);
+ BIND_ENUM_CONSTANT(FORMAT_ETC2_R11);
+ BIND_ENUM_CONSTANT(FORMAT_ETC2_R11S);
BIND_ENUM_CONSTANT(FORMAT_ETC2_RG11);
BIND_ENUM_CONSTANT(FORMAT_ETC2_RG11S);
BIND_ENUM_CONSTANT(FORMAT_ETC2_RGB8);
@@ -4177,7 +4192,7 @@ void Image::renormalize_half(uint16_t *p_rgb) {
}
void Image::renormalize_rgbe9995(uint32_t *p_rgb) {
- // Never used
+ // Never used.
}
Image::Image(const uint8_t *p_mem_png_jpg, int p_len) {
@@ -4210,6 +4225,15 @@ void Image::set_as_black() {
memset(data.ptrw(), 0, data.size());
}
+void Image::copy_internals_from(const Ref<Image> &p_image) {
+ ERR_FAIL_COND_MSG(p_image.is_null(), "Cannot copy image internals: invalid Image object.");
+ format = p_image->format;
+ width = p_image->width;
+ height = p_image->height;
+ mipmaps = p_image->mipmaps;
+ data = p_image->data;
+}
+
Dictionary Image::compute_image_metrics(const Ref<Image> p_compared_image, bool p_luma_metric) {
// https://github.com/richgel999/bc7enc_rdo/blob/master/LICENSE
//
@@ -4250,8 +4274,6 @@ Dictionary Image::compute_image_metrics(const Ref<Image> p_compared_image, bool
}
ERR_FAIL_COND_V(err != OK, result);
- ERR_FAIL_COND_V(err != OK, result);
-
ERR_FAIL_COND_V_MSG((compared_image->get_format() >= Image::FORMAT_RH) && (compared_image->get_format() <= Image::FORMAT_RGBE9995), result, "Metrics on HDR images are not supported.");
ERR_FAIL_COND_V_MSG((source_image->get_format() >= Image::FORMAT_RH) && (source_image->get_format() <= Image::FORMAT_RGBE9995), result, "Metrics on HDR images are not supported.");
diff --git a/core/io/image.h b/core/io/image.h
index 78757246e0..3149314ad8 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -43,12 +43,17 @@
class Image;
+// Function pointer prototypes.
+
typedef Error (*SavePNGFunc)(const String &p_path, const Ref<Image> &p_img);
typedef Vector<uint8_t> (*SavePNGBufferFunc)(const Ref<Image> &p_img);
+
typedef Error (*SaveJPGFunc)(const String &p_path, const Ref<Image> &p_img, float p_quality);
typedef Vector<uint8_t> (*SaveJPGBufferFunc)(const Ref<Image> &p_img, float p_quality);
+
typedef Ref<Image> (*ImageMemLoadFunc)(const uint8_t *p_png, int p_size);
typedef Ref<Image> (*ScalableImageMemLoadFunc)(const uint8_t *p_data, int p_size, float p_scale);
+
typedef Error (*SaveWebPFunc)(const String &p_path, const Ref<Image> &p_img, const bool p_lossy, const float p_quality);
typedef Vector<uint8_t> (*SaveWebPBufferFunc)(const Ref<Image> &p_img, const bool p_lossy, const float p_quality);
@@ -59,57 +64,48 @@ class Image : public Resource {
GDCLASS(Image, Resource);
public:
- static SavePNGFunc save_png_func;
- static SaveJPGFunc save_jpg_func;
- static SaveEXRFunc save_exr_func;
- static SavePNGBufferFunc save_png_buffer_func;
- static SaveEXRBufferFunc save_exr_buffer_func;
- static SaveJPGBufferFunc save_jpg_buffer_func;
- static SaveWebPFunc save_webp_func;
- static SaveWebPBufferFunc save_webp_buffer_func;
-
enum {
- MAX_WIDTH = (1 << 24), // force a limit somehow
- MAX_HEIGHT = (1 << 24), // force a limit somehow
- MAX_PIXELS = 268435456
+ MAX_WIDTH = (1 << 24), // Force a limit somehow.
+ MAX_HEIGHT = (1 << 24), // Force a limit somehow.
+ MAX_PIXELS = 268435456 // 16384 ^ 2
};
enum Format {
- FORMAT_L8, //luminance
- FORMAT_LA8, //luminance-alpha
+ FORMAT_L8, // Luminance
+ FORMAT_LA8, // Luminance-Alpha
FORMAT_R8,
FORMAT_RG8,
FORMAT_RGB8,
FORMAT_RGBA8,
FORMAT_RGBA4444,
FORMAT_RGB565,
- FORMAT_RF, //float
+ FORMAT_RF, // Float
FORMAT_RGF,
FORMAT_RGBF,
FORMAT_RGBAF,
- FORMAT_RH, //half float
+ FORMAT_RH, // Half
FORMAT_RGH,
FORMAT_RGBH,
FORMAT_RGBAH,
FORMAT_RGBE9995,
- FORMAT_DXT1, //s3tc bc1
- FORMAT_DXT3, //bc2
- FORMAT_DXT5, //bc3
- FORMAT_RGTC_R,
- FORMAT_RGTC_RG,
- FORMAT_BPTC_RGBA, //btpc bc7
- FORMAT_BPTC_RGBF, //float bc6h
- FORMAT_BPTC_RGBFU, //unsigned float bc6hu
- FORMAT_ETC, //etc1
- FORMAT_ETC2_R11, //etc2
- FORMAT_ETC2_R11S, //signed, NOT srgb.
+ FORMAT_DXT1, // BC1
+ FORMAT_DXT3, // BC2
+ FORMAT_DXT5, // BC3
+ FORMAT_RGTC_R, // BC4
+ FORMAT_RGTC_RG, // BC5
+ FORMAT_BPTC_RGBA, // BC7
+ FORMAT_BPTC_RGBF, // BC6 Signed
+ FORMAT_BPTC_RGBFU, // BC6 Unsigned
+ FORMAT_ETC, // ETC1
+ FORMAT_ETC2_R11,
+ FORMAT_ETC2_R11S, // Signed, NOT srgb.
FORMAT_ETC2_RG11,
- FORMAT_ETC2_RG11S,
+ FORMAT_ETC2_RG11S, // Signed, NOT srgb.
FORMAT_ETC2_RGB8,
FORMAT_ETC2_RGBA8,
FORMAT_ETC2_RGB8A1,
- FORMAT_ETC2_RA_AS_RG, //used to make basis universal happy
- FORMAT_DXT5_RA_AS_RG, //used to make basis universal happy
+ FORMAT_ETC2_RA_AS_RG, // ETC2 RGBA with a RA-RG swizzle for normal maps.
+ FORMAT_DXT5_RA_AS_RG, // BC3 with a RA-RG swizzle for normal maps.
FORMAT_ASTC_4x4,
FORMAT_ASTC_4x4_HDR,
FORMAT_ASTC_8x8,
@@ -118,17 +114,18 @@ public:
};
static const char *format_names[FORMAT_MAX];
+
enum Interpolation {
INTERPOLATE_NEAREST,
INTERPOLATE_BILINEAR,
INTERPOLATE_CUBIC,
INTERPOLATE_TRILINEAR,
INTERPOLATE_LANCZOS,
- /* INTERPOLATE_TRICUBIC, */
- /* INTERPOLATE GAUSS */
+ // INTERPOLATE_TRICUBIC,
+ // INTERPOLATE_GAUSS
};
- //this is used for compression
+ // Used for obtaining optimal compression quality.
enum UsedChannels {
USED_CHANNELS_L,
USED_CHANNELS_LA,
@@ -137,13 +134,66 @@ public:
USED_CHANNELS_RGB,
USED_CHANNELS_RGBA,
};
- //some functions provided by something else
+ // ASTC supports block formats other than 4x4.
enum ASTCFormat {
ASTC_FORMAT_4x4,
ASTC_FORMAT_8x8,
};
+ enum RoughnessChannel {
+ ROUGHNESS_CHANNEL_R,
+ ROUGHNESS_CHANNEL_G,
+ ROUGHNESS_CHANNEL_B,
+ ROUGHNESS_CHANNEL_A,
+ ROUGHNESS_CHANNEL_L,
+ };
+
+ enum Image3DValidateError {
+ VALIDATE_3D_OK,
+ VALIDATE_3D_ERR_IMAGE_EMPTY,
+ VALIDATE_3D_ERR_MISSING_IMAGES,
+ VALIDATE_3D_ERR_EXTRA_IMAGES,
+ VALIDATE_3D_ERR_IMAGE_SIZE_MISMATCH,
+ VALIDATE_3D_ERR_IMAGE_FORMAT_MISMATCH,
+ VALIDATE_3D_ERR_IMAGE_HAS_MIPMAPS,
+ };
+
+ enum CompressMode {
+ COMPRESS_S3TC,
+ COMPRESS_ETC,
+ COMPRESS_ETC2,
+ COMPRESS_BPTC,
+ COMPRESS_ASTC,
+ COMPRESS_MAX,
+ };
+
+ enum CompressSource {
+ COMPRESS_SOURCE_GENERIC,
+ COMPRESS_SOURCE_SRGB,
+ COMPRESS_SOURCE_NORMAL,
+ COMPRESS_SOURCE_MAX,
+ };
+
+ enum AlphaMode {
+ ALPHA_NONE,
+ ALPHA_BIT,
+ ALPHA_BLEND
+ };
+
+ // External saver function pointers.
+
+ static SavePNGFunc save_png_func;
+ static SaveJPGFunc save_jpg_func;
+ static SaveEXRFunc save_exr_func;
+ static SaveWebPFunc save_webp_func;
+ static SavePNGBufferFunc save_png_buffer_func;
+ static SaveEXRBufferFunc save_exr_buffer_func;
+ static SaveJPGBufferFunc save_jpg_buffer_func;
+ static SaveWebPBufferFunc save_webp_buffer_func;
+
+ // External loader function pointers.
+
static ImageMemLoadFunc _png_mem_loader_func;
static ImageMemLoadFunc _png_mem_unpacker_func;
static ImageMemLoadFunc _jpg_mem_loader_func;
@@ -153,6 +203,8 @@ public:
static ScalableImageMemLoadFunc _svg_scalable_mem_loader_func;
static ImageMemLoadFunc _ktx_mem_loader_func;
+ // External VRAM compression function pointers.
+
static void (*_image_compress_bc_func)(Image *, UsedChannels p_channels);
static void (*_image_compress_bptc_func)(Image *, UsedChannels p_channels);
static void (*_image_compress_etc1_func)(Image *);
@@ -162,24 +214,26 @@ public:
static Error (*_image_compress_bptc_rd_func)(Image *, UsedChannels p_channels);
static Error (*_image_compress_bc_rd_func)(Image *, UsedChannels p_channels);
+ // External VRAM decompression function pointers.
+
static void (*_image_decompress_bc)(Image *);
static void (*_image_decompress_bptc)(Image *);
static void (*_image_decompress_etc1)(Image *);
static void (*_image_decompress_etc2)(Image *);
static void (*_image_decompress_astc)(Image *);
+ // External packer function pointers.
+
static Vector<uint8_t> (*webp_lossy_packer)(const Ref<Image> &p_image, float p_quality);
static Vector<uint8_t> (*webp_lossless_packer)(const Ref<Image> &p_image);
- static Ref<Image> (*webp_unpacker)(const Vector<uint8_t> &p_buffer);
static Vector<uint8_t> (*png_packer)(const Ref<Image> &p_image);
- static Ref<Image> (*png_unpacker)(const Vector<uint8_t> &p_buffer);
static Vector<uint8_t> (*basis_universal_packer)(const Ref<Image> &p_image, UsedChannels p_channels);
+
+ static Ref<Image> (*webp_unpacker)(const Vector<uint8_t> &p_buffer);
+ static Ref<Image> (*png_unpacker)(const Vector<uint8_t> &p_buffer);
static Ref<Image> (*basis_universal_unpacker)(const Vector<uint8_t> &p_buffer);
static Ref<Image> (*basis_universal_unpacker_ptr)(const uint8_t *p_data, int p_size);
- _FORCE_INLINE_ Color _get_color_at_ofs(const uint8_t *ptr, uint32_t ofs) const;
- _FORCE_INLINE_ void _set_color_at_ofs(uint8_t *ptr, uint32_t ofs, const Color &p_color);
-
protected:
static void _bind_methods();
@@ -190,15 +244,12 @@ private:
int height = 0;
bool mipmaps = false;
- void _copy_internals_from(const Image &p_image) {
- format = p_image.format;
- width = p_image.width;
- height = p_image.height;
- mipmaps = p_image.mipmaps;
- data = p_image.data;
- }
+ void _copy_internals_from(const Image &p_image);
+
+ _FORCE_INLINE_ Color _get_color_at_ofs(const uint8_t *ptr, uint32_t ofs) const;
+ _FORCE_INLINE_ void _set_color_at_ofs(uint8_t *ptr, uint32_t ofs, const Color &p_color);
- _FORCE_INLINE_ void _get_mipmap_offset_and_size(int p_mipmap, int64_t &r_offset, int &r_width, int &r_height) const; //get where the mipmap begins in data
+ _FORCE_INLINE_ void _get_mipmap_offset_and_size(int p_mipmap, int64_t &r_offset, int &r_width, int &r_height) const; // Get where the mipmap begins in data.
static int64_t _get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps = -1, int *r_mm_width = nullptr, int *r_mm_height = nullptr);
bool _can_modify(Format p_format) const;
@@ -225,52 +276,32 @@ private:
static void renormalize_rgbe9995(uint32_t *p_rgb);
public:
- int get_width() const; ///< Get image width
- int get_height() const; ///< Get image height
+ int get_width() const;
+ int get_height() const;
Size2i get_size() const;
bool has_mipmaps() const;
int get_mipmap_count() const;
- /**
- * Convert the image to another format, conversion only to raw byte format
- */
+ // Convert the image to another format, conversion only to raw byte format.
void convert(Format p_new_format);
- /**
- * Get the current image format.
- */
Format get_format() const;
- /**
- * Get where the mipmap begins in data.
- */
+ // Get where the mipmap begins in data.
int64_t get_mipmap_offset(int p_mipmap) const;
void get_mipmap_offset_and_size(int p_mipmap, int64_t &r_ofs, int64_t &r_size) const;
void get_mipmap_offset_size_and_dimensions(int p_mipmap, int64_t &r_ofs, int64_t &r_size, int &w, int &h) const;
- enum Image3DValidateError {
- VALIDATE_3D_OK,
- VALIDATE_3D_ERR_IMAGE_EMPTY,
- VALIDATE_3D_ERR_MISSING_IMAGES,
- VALIDATE_3D_ERR_EXTRA_IMAGES,
- VALIDATE_3D_ERR_IMAGE_SIZE_MISMATCH,
- VALIDATE_3D_ERR_IMAGE_FORMAT_MISMATCH,
- VALIDATE_3D_ERR_IMAGE_HAS_MIPMAPS,
- };
-
static Image3DValidateError validate_3d_image(Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_images);
static String get_3d_image_validation_error_text(Image3DValidateError p_error);
- /**
- * Resize the image, using the preferred interpolation method.
- */
+ // Resize the image, using the preferred interpolation method.
void resize_to_po2(bool p_square = false, Interpolation p_interpolation = INTERPOLATE_BILINEAR);
void resize(int p_width, int p_height, Interpolation p_interpolation = INTERPOLATE_BILINEAR);
void shrink_x2();
bool is_size_po2() const;
- /**
- * Crop the image to a specific size, if larger, then the image is filled by black
- */
+
+ // Crop the image to a specific size, if larger, then the image is filled by black.
void crop_from_point(int p_x, int p_y, int p_width, int p_height);
void crop(int p_width, int p_height);
@@ -280,34 +311,20 @@ public:
void flip_x();
void flip_y();
- /**
- * Generate a mipmap to an image (creates an image 1/4 the size, with averaging of 4->1)
- */
+ // Generate a mipmap chain of an image (creates an image 1/4 the size, with averaging of 4->1).
Error generate_mipmaps(bool p_renormalize = false);
- enum RoughnessChannel {
- ROUGHNESS_CHANNEL_R,
- ROUGHNESS_CHANNEL_G,
- ROUGHNESS_CHANNEL_B,
- ROUGHNESS_CHANNEL_A,
- ROUGHNESS_CHANNEL_L,
- };
-
Error generate_mipmap_roughness(RoughnessChannel p_roughness_channel, const Ref<Image> &p_normal_map);
void clear_mipmaps();
- void normalize(); //for normal maps
+ void normalize();
- /**
- * Creates new internal image data of a given size and format. Current image will be lost.
- */
+ // Creates new internal image data of a given size and format. Current image will be lost.
void initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
void initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
void initialize_data(const char **p_xpm);
- /**
- * returns true when the image is empty (0,0) in size
- */
+ // Returns true when the image is empty (0,0) in size.
bool is_empty() const;
Vector<uint8_t> get_data() const;
@@ -327,27 +344,14 @@ public:
static Ref<Image> create_from_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
void set_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
- /**
- * create an empty image
- */
- Image() {}
- /**
- * create an empty image of a specific size and format
- */
- Image(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
- /**
- * import an image of a specific size and format from a pointer
- */
- Image(int p_width, int p_height, bool p_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
+ Image() = default; // Create an empty image.
+ Image(int p_width, int p_height, bool p_use_mipmaps, Format p_format); // Create an empty image of a specific size and format.
+ Image(int p_width, int p_height, bool p_mipmaps, Format p_format, const Vector<uint8_t> &p_data); // Import an image of a specific size and format from a byte vector.
+ Image(const uint8_t *p_mem_png_jpg, int p_len = -1); // Import either a png or jpg from a pointer.
+ Image(const char **p_xpm); // Import an XPM image.
~Image() {}
- enum AlphaMode {
- ALPHA_NONE,
- ALPHA_BIT,
- ALPHA_BLEND
- };
-
AlphaMode detect_alpha() const;
bool is_invisible() const;
@@ -362,21 +366,6 @@ public:
static int64_t get_image_mipmap_offset(int p_width, int p_height, Format p_format, int p_mipmap);
static int64_t get_image_mipmap_offset_and_dimensions(int p_width, int p_height, Format p_format, int p_mipmap, int &r_w, int &r_h);
- enum CompressMode {
- COMPRESS_S3TC,
- COMPRESS_ETC,
- COMPRESS_ETC2,
- COMPRESS_BPTC,
- COMPRESS_ASTC,
- COMPRESS_MAX,
- };
- enum CompressSource {
- COMPRESS_SOURCE_GENERIC,
- COMPRESS_SOURCE_SRGB,
- COMPRESS_SOURCE_NORMAL,
- COMPRESS_SOURCE_MAX,
- };
-
Error compress(CompressMode p_mode, CompressSource p_source = COMPRESS_SOURCE_GENERIC, ASTCFormat p_astc_format = ASTC_FORMAT_4x4);
Error compress_from_channels(CompressMode p_mode, UsedChannels p_channels, ASTCFormat p_astc_format = ASTC_FORMAT_4x4);
Error decompress();
@@ -422,9 +411,6 @@ public:
void convert_ra_rgba8_to_rg();
void convert_rgba8_to_bgra8();
- Image(const uint8_t *p_mem_png_jpg, int p_len = -1);
- Image(const char **p_xpm);
-
virtual Ref<Resource> duplicate(bool p_subresources = false) const override;
UsedChannels detect_used_channels(CompressSource p_source = COMPRESS_SOURCE_GENERIC) const;
@@ -443,14 +429,7 @@ public:
void set_as_black();
- void copy_internals_from(const Ref<Image> &p_image) {
- ERR_FAIL_COND_MSG(p_image.is_null(), "Cannot copy image internals: invalid Image object.");
- format = p_image->format;
- width = p_image->width;
- height = p_image->height;
- mipmaps = p_image->mipmaps;
- data = p_image->data;
- }
+ void copy_internals_from(const Ref<Image> &p_image);
Dictionary compute_image_metrics(const Ref<Image> p_compared_image, bool p_luma_metric = true);
};
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index 50c4704aa3..58e63a4cc9 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -82,15 +82,16 @@ void ImageFormatLoaderExtension::_bind_methods() {
Error ImageLoader::load_image(const String &p_file, Ref<Image> p_image, Ref<FileAccess> p_custom, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
ERR_FAIL_COND_V_MSG(p_image.is_null(), ERR_INVALID_PARAMETER, "Can't load an image: invalid Image object.");
+ const String file = ResourceUID::ensure_path(p_file);
Ref<FileAccess> f = p_custom;
if (f.is_null()) {
Error err;
- f = FileAccess::open(p_file, FileAccess::READ, &err);
- ERR_FAIL_COND_V_MSG(f.is_null(), err, vformat("Error opening file '%s'.", p_file));
+ f = FileAccess::open(file, FileAccess::READ, &err);
+ ERR_FAIL_COND_V_MSG(f.is_null(), err, vformat("Error opening file '%s'.", file));
}
- String extension = p_file.get_extension();
+ String extension = file.get_extension();
for (int i = 0; i < loader.size(); i++) {
if (!loader[i]->recognize(extension)) {
@@ -98,7 +99,7 @@ Error ImageLoader::load_image(const String &p_file, Ref<Image> p_image, Ref<File
}
Error err = loader.write[i]->load_image(p_image, f, p_flags, p_scale);
if (err != OK) {
- ERR_PRINT(vformat("Error loading image: '%s'.", p_file));
+ ERR_PRINT(vformat("Error loading image: '%s'.", file));
}
if (err != ERR_FILE_UNRECOGNIZED) {
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
index c4d11b8a32..d9664e7370 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -33,8 +33,6 @@
#include "core/io/resource_loader.h"
#include "core/object/ref_counted.h"
#include "core/object/script_language.h"
-#include "core/os/keyboard.h"
-#include "core/string/print_string.h"
#include <limits.h>
#include <stdio.h>
@@ -69,10 +67,31 @@ ObjectID EncodedObjectAsID::get_object_id() const {
// For `Variant::ARRAY`.
// Occupies bits 16 and 17.
#define HEADER_DATA_FIELD_TYPED_ARRAY_MASK (0b11 << 16)
-#define HEADER_DATA_FIELD_TYPED_ARRAY_NONE (0b00 << 16)
-#define HEADER_DATA_FIELD_TYPED_ARRAY_BUILTIN (0b01 << 16)
-#define HEADER_DATA_FIELD_TYPED_ARRAY_CLASS_NAME (0b10 << 16)
-#define HEADER_DATA_FIELD_TYPED_ARRAY_SCRIPT (0b11 << 16)
+#define HEADER_DATA_FIELD_TYPED_ARRAY_SHIFT 16
+
+// For `Variant::DICTIONARY`.
+// Occupies bits 16 and 17.
+#define HEADER_DATA_FIELD_TYPED_DICTIONARY_KEY_MASK (0b11 << 16)
+#define HEADER_DATA_FIELD_TYPED_DICTIONARY_KEY_SHIFT 16
+// Occupies bits 18 and 19.
+#define HEADER_DATA_FIELD_TYPED_DICTIONARY_VALUE_MASK (0b11 << 18)
+#define HEADER_DATA_FIELD_TYPED_DICTIONARY_VALUE_SHIFT 18
+
+enum ContainerTypeKind {
+ CONTAINER_TYPE_KIND_NONE = 0b00,
+ CONTAINER_TYPE_KIND_BUILTIN = 0b01,
+ CONTAINER_TYPE_KIND_CLASS_NAME = 0b10,
+ CONTAINER_TYPE_KIND_SCRIPT = 0b11,
+};
+
+struct ContainerType {
+ Variant::Type builtin_type = Variant::NIL;
+ StringName class_name;
+ Ref<Script> script;
+};
+
+#define GET_CONTAINER_TYPE_KIND(m_header, m_field) \
+ ((ContainerTypeKind)(((m_header) & HEADER_DATA_FIELD_##m_field##_MASK) >> HEADER_DATA_FIELD_##m_field##_SHIFT))
static Error _decode_string(const uint8_t *&buf, int &len, int *r_len, String &r_string) {
ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);
@@ -80,7 +99,7 @@ static Error _decode_string(const uint8_t *&buf, int &len, int *r_len, String &r
int32_t strlen = decode_uint32(buf);
int32_t pad = 0;
- // Handle padding
+ // Handle padding.
if (strlen % 4) {
pad = 4 - strlen % 4;
}
@@ -88,7 +107,7 @@ static Error _decode_string(const uint8_t *&buf, int &len, int *r_len, String &r
buf += 4;
len -= 4;
- // Ensure buffer is big enough
+ // Ensure buffer is big enough.
ERR_FAIL_ADD_OF(strlen, pad, ERR_FILE_EOF);
ERR_FAIL_COND_V(strlen < 0 || strlen + pad > len, ERR_FILE_EOF);
@@ -96,10 +115,10 @@ static Error _decode_string(const uint8_t *&buf, int &len, int *r_len, String &r
ERR_FAIL_COND_V(str.parse_utf8((const char *)buf, strlen) != OK, ERR_INVALID_DATA);
r_string = str;
- // Add padding
+ // Add padding.
strlen += pad;
- // Update buffer pos, left data count, and return size
+ // Update buffer pos, left data count, and return size.
buf += strlen;
len -= strlen;
if (r_len) {
@@ -109,6 +128,65 @@ static Error _decode_string(const uint8_t *&buf, int &len, int *r_len, String &r
return OK;
}
+static Error _decode_container_type(const uint8_t *&buf, int &len, int *r_len, bool p_allow_objects, ContainerTypeKind p_type_kind, ContainerType &r_type) {
+ switch (p_type_kind) {
+ case CONTAINER_TYPE_KIND_NONE: {
+ return OK;
+ } break;
+ case CONTAINER_TYPE_KIND_BUILTIN: {
+ ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);
+
+ int32_t bt = decode_uint32(buf);
+ buf += 4;
+ len -= 4;
+ if (r_len) {
+ (*r_len) += 4;
+ }
+
+ ERR_FAIL_INDEX_V(bt, Variant::VARIANT_MAX, ERR_INVALID_DATA);
+ r_type.builtin_type = (Variant::Type)bt;
+ if (!p_allow_objects && r_type.builtin_type == Variant::OBJECT) {
+ r_type.class_name = EncodedObjectAsID::get_class_static();
+ }
+ return OK;
+ } break;
+ case CONTAINER_TYPE_KIND_CLASS_NAME: {
+ String str;
+ Error err = _decode_string(buf, len, r_len, str);
+ if (err) {
+ return err;
+ }
+
+ r_type.builtin_type = Variant::OBJECT;
+ if (p_allow_objects) {
+ r_type.class_name = str;
+ } else {
+ r_type.class_name = EncodedObjectAsID::get_class_static();
+ }
+ return OK;
+ } break;
+ case CONTAINER_TYPE_KIND_SCRIPT: {
+ String path;
+ Error err = _decode_string(buf, len, r_len, path);
+ if (err) {
+ return err;
+ }
+
+ r_type.builtin_type = Variant::OBJECT;
+ if (p_allow_objects) {
+ ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://") || !ResourceLoader::exists(path, "Script"), ERR_INVALID_DATA, vformat("Invalid script path \"%s\".", path));
+ r_type.script = ResourceLoader::load(path, "Script");
+ ERR_FAIL_COND_V_MSG(r_type.script.is_null(), ERR_INVALID_DATA, vformat("Can't load script at path \"%s\".", path));
+ r_type.class_name = r_type.script->get_instance_base_type();
+ } else {
+ r_type.class_name = EncodedObjectAsID::get_class_static();
+ }
+ return OK;
+ } break;
+ }
+ ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Invalid container type kind."); // Future proofing.
+}
+
Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len, bool p_allow_objects, int p_depth) {
ERR_FAIL_COND_V_MSG(p_depth > Variant::MAX_RECURSION_DEPTH, ERR_OUT_OF_MEMORY, "Variant is too deep. Bailing.");
const uint8_t *buf = p_buffer;
@@ -126,7 +204,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
*r_len = 4;
}
- // Note: We cannot use sizeof(real_t) for decoding, in case a different size is encoded.
+ // NOTE: We cannot use `sizeof(real_t)` for decoding, in case a different size is encoded.
// Decoding math types always checks for the encoded size, while encoding always uses compilation setting.
// This does lead to some code duplication for decoding, but compatibility is the priority.
switch (header & HEADER_TYPE_MASK) {
@@ -188,7 +266,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
} break;
- // math types
+ // Math types.
case Variant::VECTOR2: {
Vector2 val;
if (header & HEADER_DATA_FLAG_64) {
@@ -539,7 +617,8 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
r_variant = val;
} break;
- // misc types
+
+ // Misc types.
case Variant::COLOR: {
ERR_FAIL_COND_V(len < 4 * 4, ERR_INVALID_DATA);
Color val;
@@ -568,7 +647,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
int32_t strlen = decode_uint32(buf);
if (strlen & 0x80000000) {
- //new format
+ // New format.
ERR_FAIL_COND_V(len < 12, ERR_INVALID_DATA);
Vector<StringName> names;
Vector<StringName> subnames;
@@ -607,8 +686,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
r_variant = NodePath(names, subnames, np_flags & 1);
} else {
- //old format, just a string
-
+ // Old format, just a string.
ERR_FAIL_V(ERR_INVALID_DATA);
}
@@ -698,9 +776,9 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
if (str == "script" && value.get_type() != Variant::NIL) {
ERR_FAIL_COND_V_MSG(value.get_type() != Variant::STRING, ERR_INVALID_DATA, "Invalid value for \"script\" property, expected script path as String.");
String path = value;
- ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://") || !ResourceLoader::exists(path, "Script"), ERR_INVALID_DATA, vformat("Invalid script path: '%s'.", path));
+ ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://") || !ResourceLoader::exists(path, "Script"), ERR_INVALID_DATA, vformat("Invalid script path \"%s\".", path));
Ref<Script> script = ResourceLoader::load(path, "Script");
- ERR_FAIL_COND_V_MSG(script.is_null(), ERR_INVALID_DATA, vformat("Can't load script at path: '%s'.", path));
+ ERR_FAIL_COND_V_MSG(script.is_null(), ERR_INVALID_DATA, vformat("Can't load script at path \"%s\".", path));
obj->set_script(script);
} else {
obj->set(str, value);
@@ -731,9 +809,30 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
r_variant = Signal(id, StringName(name));
} break;
case Variant::DICTIONARY: {
+ ContainerType key_type;
+
+ {
+ ContainerTypeKind key_type_kind = GET_CONTAINER_TYPE_KIND(header, TYPED_DICTIONARY_KEY);
+ Error err = _decode_container_type(buf, len, r_len, p_allow_objects, key_type_kind, key_type);
+ if (err) {
+ return err;
+ }
+ }
+
+ ContainerType value_type;
+
+ {
+ ContainerTypeKind value_type_kind = GET_CONTAINER_TYPE_KIND(header, TYPED_DICTIONARY_VALUE);
+ Error err = _decode_container_type(buf, len, r_len, p_allow_objects, value_type_kind, value_type);
+ if (err) {
+ return err;
+ }
+ }
+
ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);
+
int32_t count = decode_uint32(buf);
- // bool shared = count&0x80000000;
+ //bool shared = count & 0x80000000;
count &= 0x7FFFFFFF;
buf += 4;
@@ -743,7 +842,10 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
(*r_len) += 4; // Size of count number.
}
- Dictionary d;
+ Dictionary dict;
+ if (key_type.builtin_type != Variant::NIL || value_type.builtin_type != Variant::NIL) {
+ dict.set_typed(key_type.builtin_type, key_type.class_name, key_type.script, value_type.builtin_type, value_type.class_name, value_type.script);
+ }
for (int i = 0; i < count; i++) {
Variant key, value;
@@ -767,75 +869,27 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
(*r_len) += used;
}
- d[key] = value;
+ dict[key] = value;
}
- r_variant = d;
+ r_variant = dict;
} break;
case Variant::ARRAY: {
- Variant::Type builtin_type = Variant::VARIANT_MAX;
- StringName class_name;
- Ref<Script> script;
-
- switch (header & HEADER_DATA_FIELD_TYPED_ARRAY_MASK) {
- case HEADER_DATA_FIELD_TYPED_ARRAY_NONE:
- break; // Untyped array.
- case HEADER_DATA_FIELD_TYPED_ARRAY_BUILTIN: {
- ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);
-
- int32_t bt = decode_uint32(buf);
- buf += 4;
- len -= 4;
- if (r_len) {
- (*r_len) += 4;
- }
+ ContainerType type;
- ERR_FAIL_INDEX_V(bt, Variant::VARIANT_MAX, ERR_INVALID_DATA);
- builtin_type = (Variant::Type)bt;
- if (!p_allow_objects && builtin_type == Variant::OBJECT) {
- class_name = EncodedObjectAsID::get_class_static();
- }
- } break;
- case HEADER_DATA_FIELD_TYPED_ARRAY_CLASS_NAME: {
- String str;
- Error err = _decode_string(buf, len, r_len, str);
- if (err) {
- return err;
- }
-
- builtin_type = Variant::OBJECT;
- if (p_allow_objects) {
- class_name = str;
- } else {
- class_name = EncodedObjectAsID::get_class_static();
- }
- } break;
- case HEADER_DATA_FIELD_TYPED_ARRAY_SCRIPT: {
- String path;
- Error err = _decode_string(buf, len, r_len, path);
- if (err) {
- return err;
- }
-
- builtin_type = Variant::OBJECT;
- if (p_allow_objects) {
- ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://") || !ResourceLoader::exists(path, "Script"), ERR_INVALID_DATA, vformat("Invalid script path: '%s'.", path));
- script = ResourceLoader::load(path, "Script");
- ERR_FAIL_COND_V_MSG(script.is_null(), ERR_INVALID_DATA, vformat("Can't load script at path: '%s'.", path));
- class_name = script->get_instance_base_type();
- } else {
- class_name = EncodedObjectAsID::get_class_static();
- }
- } break;
- default:
- ERR_FAIL_V(ERR_INVALID_DATA); // Future proofing.
+ {
+ ContainerTypeKind type_kind = GET_CONTAINER_TYPE_KIND(header, TYPED_ARRAY);
+ Error err = _decode_container_type(buf, len, r_len, p_allow_objects, type_kind, type);
+ if (err) {
+ return err;
+ }
}
ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);
int32_t count = decode_uint32(buf);
- // bool shared = count&0x80000000;
+ //bool shared = count & 0x80000000;
count &= 0x7FFFFFFF;
buf += 4;
@@ -845,29 +899,29 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
(*r_len) += 4; // Size of count number.
}
- Array varr;
- if (builtin_type != Variant::VARIANT_MAX) {
- varr.set_typed(builtin_type, class_name, script);
+ Array array;
+ if (type.builtin_type != Variant::NIL) {
+ array.set_typed(type.builtin_type, type.class_name, type.script);
}
for (int i = 0; i < count; i++) {
int used = 0;
- Variant v;
- Error err = decode_variant(v, buf, len, &used, p_allow_objects, p_depth + 1);
+ Variant elem;
+ Error err = decode_variant(elem, buf, len, &used, p_allow_objects, p_depth + 1);
ERR_FAIL_COND_V_MSG(err != OK, err, "Error when trying to decode Variant.");
buf += used;
len -= used;
- varr.push_back(v);
+ array.push_back(elem);
if (r_len) {
(*r_len) += used;
}
}
- r_variant = varr;
+ r_variant = array;
} break;
- // arrays
+ // Packed arrays.
case Variant::PACKED_BYTE_ARRAY: {
ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);
int32_t count = decode_uint32(buf);
@@ -906,7 +960,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
Vector<int32_t> data;
if (count) {
- //const int*rbuf=(const int*)buf;
+ //const int *rbuf = (const int *)buf;
data.resize(count);
int32_t *w = data.ptrw();
for (int32_t i = 0; i < count; i++) {
@@ -930,7 +984,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
Vector<int64_t> data;
if (count) {
- //const int*rbuf=(const int*)buf;
+ //const int *rbuf = (const int *)buf;
data.resize(count);
int64_t *w = data.ptrw();
for (int64_t i = 0; i < count; i++) {
@@ -954,7 +1008,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
Vector<float> data;
if (count) {
- //const float*rbuf=(const float*)buf;
+ //const float *rbuf = (const float *)buf;
data.resize(count);
float *w = data.ptrw();
for (int32_t i = 0; i < count; i++) {
@@ -1265,13 +1319,50 @@ static void _encode_string(const String &p_string, uint8_t *&buf, int &r_len) {
r_len += 4 + utf8.length();
while (r_len % 4) {
- r_len++; //pad
+ r_len++; // Pad.
if (buf) {
*(buf++) = 0;
}
}
}
+static void _encode_container_type_header(const ContainerType &p_type, uint32_t &header, uint32_t p_shift, bool p_full_objects) {
+ if (p_type.builtin_type != Variant::NIL) {
+ if (p_type.script.is_valid()) {
+ header |= (p_full_objects ? CONTAINER_TYPE_KIND_SCRIPT : CONTAINER_TYPE_KIND_CLASS_NAME) << p_shift;
+ } else if (p_type.class_name != StringName()) {
+ header |= CONTAINER_TYPE_KIND_CLASS_NAME << p_shift;
+ } else {
+ // No need to check `p_full_objects` since `class_name` should be non-empty for `builtin_type == Variant::OBJECT`.
+ header |= CONTAINER_TYPE_KIND_BUILTIN << p_shift;
+ }
+ }
+}
+
+static Error _encode_container_type(const ContainerType &p_type, uint8_t *&buf, int &r_len, bool p_full_objects) {
+ if (p_type.builtin_type != Variant::NIL) {
+ if (p_type.script.is_valid()) {
+ if (p_full_objects) {
+ String path = p_type.script->get_path();
+ ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://"), ERR_UNAVAILABLE, "Failed to encode a path to a custom script for a container type.");
+ _encode_string(path, buf, r_len);
+ } else {
+ _encode_string(EncodedObjectAsID::get_class_static(), buf, r_len);
+ }
+ } else if (p_type.class_name != StringName()) {
+ _encode_string(p_full_objects ? p_type.class_name.operator String() : EncodedObjectAsID::get_class_static(), buf, r_len);
+ } else {
+ // No need to check `p_full_objects` since `class_name` should be non-empty for `builtin_type == Variant::OBJECT`.
+ if (buf) {
+ encode_uint32(p_type.builtin_type, buf);
+ buf += 4;
+ }
+ r_len += 4;
+ }
+ }
+ return OK;
+}
+
Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects, int p_depth) {
ERR_FAIL_COND_V_MSG(p_depth > Variant::MAX_RECURSION_DEPTH, ERR_OUT_OF_MEMORY, "Potential infinite recursion detected. Bailing.");
uint8_t *buf = r_buffer;
@@ -1310,20 +1401,32 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
header |= HEADER_DATA_FLAG_OBJECT_AS_ID;
}
} break;
+ case Variant::DICTIONARY: {
+ Dictionary dict = p_variant;
+
+ ContainerType key_type;
+ key_type.builtin_type = (Variant::Type)dict.get_typed_key_builtin();
+ key_type.class_name = dict.get_typed_key_class_name();
+ key_type.script = dict.get_typed_key_script();
+
+ _encode_container_type_header(key_type, header, HEADER_DATA_FIELD_TYPED_DICTIONARY_KEY_SHIFT, p_full_objects);
+
+ ContainerType value_type;
+ value_type.builtin_type = (Variant::Type)dict.get_typed_value_builtin();
+ value_type.class_name = dict.get_typed_value_class_name();
+ value_type.script = dict.get_typed_value_script();
+
+ _encode_container_type_header(value_type, header, HEADER_DATA_FIELD_TYPED_DICTIONARY_VALUE_SHIFT, p_full_objects);
+ } break;
case Variant::ARRAY: {
Array array = p_variant;
- if (array.is_typed()) {
- Ref<Script> script = array.get_typed_script();
- if (script.is_valid()) {
- header |= p_full_objects ? HEADER_DATA_FIELD_TYPED_ARRAY_SCRIPT : HEADER_DATA_FIELD_TYPED_ARRAY_CLASS_NAME;
- } else if (array.get_typed_class_name() != StringName()) {
- header |= HEADER_DATA_FIELD_TYPED_ARRAY_CLASS_NAME;
- } else {
- // No need to check `p_full_objects` since for `Variant::OBJECT`
- // `array.get_typed_class_name()` should be non-empty.
- header |= HEADER_DATA_FIELD_TYPED_ARRAY_BUILTIN;
- }
- }
+
+ ContainerType type;
+ type.builtin_type = (Variant::Type)array.get_typed_builtin();
+ type.class_name = array.get_typed_class_name();
+ type.script = array.get_typed_script();
+
+ _encode_container_type_header(type, header, HEADER_DATA_FIELD_TYPED_ARRAY_SHIFT, p_full_objects);
} break;
#ifdef REAL_T_IS_DOUBLE
case Variant::VECTOR2:
@@ -1344,7 +1447,8 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
} break;
#endif // REAL_T_IS_DOUBLE
default: {
- } // nothing to do at this stage
+ // Nothing to do at this stage.
+ } break;
}
if (buf) {
@@ -1355,7 +1459,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
switch (p_variant.get_type()) {
case Variant::NIL: {
- //nothing to do
+ // Nothing to do.
} break;
case Variant::BOOL: {
if (buf) {
@@ -1367,7 +1471,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
} break;
case Variant::INT: {
if (header & HEADER_DATA_FLAG_64) {
- //64 bits
+ // 64 bits.
if (buf) {
encode_uint64(p_variant.operator int64_t(), buf);
}
@@ -1401,7 +1505,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
case Variant::NODE_PATH: {
NodePath np = p_variant;
if (buf) {
- encode_uint32(uint32_t(np.get_name_count()) | 0x80000000, buf); //for compatibility with the old format
+ encode_uint32(uint32_t(np.get_name_count()) | 0x80000000, buf); // For compatibility with the old format.
encode_uint32(np.get_subname_count(), buf + 4);
uint32_t np_flags = 0;
if (np.is_absolute()) {
@@ -1451,7 +1555,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
} break;
- // math types
+ // Math types.
case Variant::VECTOR2: {
if (buf) {
Vector2 v2 = p_variant;
@@ -1635,7 +1739,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
} break;
- // misc types
+ // Misc types.
case Variant::COLOR: {
if (buf) {
Color c = p_variant;
@@ -1746,29 +1850,53 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
r_len += 8;
} break;
case Variant::DICTIONARY: {
- Dictionary d = p_variant;
+ Dictionary dict = p_variant;
+
+ {
+ ContainerType key_type;
+ key_type.builtin_type = (Variant::Type)dict.get_typed_key_builtin();
+ key_type.class_name = dict.get_typed_key_class_name();
+ key_type.script = dict.get_typed_key_script();
+
+ Error err = _encode_container_type(key_type, buf, r_len, p_full_objects);
+ if (err) {
+ return err;
+ }
+ }
+
+ {
+ ContainerType value_type;
+ value_type.builtin_type = (Variant::Type)dict.get_typed_value_builtin();
+ value_type.class_name = dict.get_typed_value_class_name();
+ value_type.script = dict.get_typed_value_script();
+
+ Error err = _encode_container_type(value_type, buf, r_len, p_full_objects);
+ if (err) {
+ return err;
+ }
+ }
if (buf) {
- encode_uint32(uint32_t(d.size()), buf);
+ encode_uint32(uint32_t(dict.size()), buf);
buf += 4;
}
r_len += 4;
List<Variant> keys;
- d.get_key_list(&keys);
+ dict.get_key_list(&keys);
- for (const Variant &E : keys) {
+ for (const Variant &key : keys) {
int len;
- Error err = encode_variant(E, buf, len, p_full_objects, p_depth + 1);
+ Error err = encode_variant(key, buf, len, p_full_objects, p_depth + 1);
ERR_FAIL_COND_V(err, err);
ERR_FAIL_COND_V(len % 4, ERR_BUG);
r_len += len;
if (buf) {
buf += len;
}
- Variant *v = d.getptr(E);
- ERR_FAIL_NULL_V(v, ERR_BUG);
- err = encode_variant(*v, buf, len, p_full_objects, p_depth + 1);
+ Variant *value = dict.getptr(key);
+ ERR_FAIL_NULL_V(value, ERR_BUG);
+ err = encode_variant(*value, buf, len, p_full_objects, p_depth + 1);
ERR_FAIL_COND_V(err, err);
ERR_FAIL_COND_V(len % 4, ERR_BUG);
r_len += len;
@@ -1781,27 +1909,15 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
case Variant::ARRAY: {
Array array = p_variant;
- if (array.is_typed()) {
- Variant variant = array.get_typed_script();
- Ref<Script> script = variant;
- if (script.is_valid()) {
- if (p_full_objects) {
- String path = script->get_path();
- ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://"), ERR_UNAVAILABLE, "Failed to encode a path to a custom script for an array type.");
- _encode_string(path, buf, r_len);
- } else {
- _encode_string(EncodedObjectAsID::get_class_static(), buf, r_len);
- }
- } else if (array.get_typed_class_name() != StringName()) {
- _encode_string(p_full_objects ? array.get_typed_class_name().operator String() : EncodedObjectAsID::get_class_static(), buf, r_len);
- } else {
- // No need to check `p_full_objects` since for `Variant::OBJECT`
- // `array.get_typed_class_name()` should be non-empty.
- if (buf) {
- encode_uint32(array.get_typed_builtin(), buf);
- buf += 4;
- }
- r_len += 4;
+ {
+ ContainerType type;
+ type.builtin_type = (Variant::Type)array.get_typed_builtin();
+ type.class_name = array.get_typed_class_name();
+ type.script = array.get_typed_script();
+
+ Error err = _encode_container_type(type, buf, r_len, p_full_objects);
+ if (err) {
+ return err;
}
}
@@ -1811,9 +1927,9 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
}
r_len += 4;
- for (const Variant &var : array) {
+ for (const Variant &elem : array) {
int len;
- Error err = encode_variant(var, buf, len, p_full_objects, p_depth + 1);
+ Error err = encode_variant(elem, buf, len, p_full_objects, p_depth + 1);
ERR_FAIL_COND_V(err, err);
ERR_FAIL_COND_V(len % 4, ERR_BUG);
if (buf) {
@@ -1823,7 +1939,8 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
}
} break;
- // arrays
+
+ // Packed arrays.
case Variant::PACKED_BYTE_ARRAY: {
Vector<uint8_t> data = p_variant;
int datalen = data.size();
@@ -1939,7 +2056,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
r_len += 4 + utf8.length() + 1;
while (r_len % 4) {
- r_len++; //pad
+ r_len++; // Pad.
if (buf) {
*(buf++) = 0;
}
@@ -2057,9 +2174,9 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
}
Vector<float> vector3_to_float32_array(const Vector3 *vecs, size_t count) {
- // We always allocate a new array, and we don't memcpy.
- // We also don't consider returning a pointer to the passed vectors when sizeof(real_t) == 4.
- // One reason is that we could decide to put a 4th component in Vector3 for SIMD/mobile performance,
+ // We always allocate a new array, and we don't `memcpy()`.
+ // We also don't consider returning a pointer to the passed vectors when `sizeof(real_t) == 4`.
+ // One reason is that we could decide to put a 4th component in `Vector3` for SIMD/mobile performance,
// which would cause trouble with these optimizations.
Vector<float> floats;
if (count == 0) {
diff --git a/core/io/marshalls.h b/core/io/marshalls.h
index 6f015ac386..82c760c28d 100644
--- a/core/io/marshalls.h
+++ b/core/io/marshalls.h
@@ -84,6 +84,12 @@ static inline unsigned int encode_uint32(uint32_t p_uint, uint8_t *p_arr) {
return sizeof(uint32_t);
}
+static inline unsigned int encode_half(float p_float, uint8_t *p_arr) {
+ encode_uint16(Math::make_half_float(p_float), p_arr);
+
+ return sizeof(uint16_t);
+}
+
static inline unsigned int encode_float(float p_float, uint8_t *p_arr) {
MarshallFloat mf;
mf.f = p_float;
@@ -172,6 +178,10 @@ static inline uint32_t decode_uint32(const uint8_t *p_arr) {
return u;
}
+static inline float decode_half(const uint8_t *p_arr) {
+ return Math::half_to_float(decode_uint16(p_arr));
+}
+
static inline float decode_float(const uint8_t *p_arr) {
MarshallFloat mf;
mf.i = decode_uint32(p_arr);
diff --git a/core/io/net_socket.h b/core/io/net_socket.h
index 120ad5e85b..c12bab622a 100644
--- a/core/io/net_socket.h
+++ b/core/io/net_socket.h
@@ -76,6 +76,8 @@ public:
virtual void set_reuse_address_enabled(bool p_enabled) = 0;
virtual Error join_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) = 0;
virtual Error leave_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) = 0;
+
+ virtual ~NetSocket() {}
};
#endif // NET_SOCKET_H
diff --git a/core/io/plist.cpp b/core/io/plist.cpp
index 32e83c31f2..26b8c39495 100644
--- a/core/io/plist.cpp
+++ b/core/io/plist.cpp
@@ -661,12 +661,12 @@ bool PList::load_string(const String &p_string, String &r_err_out) {
List<Ref<PListNode>> stack;
String key;
while (pos >= 0) {
- int open_token_s = p_string.find("<", pos);
+ int open_token_s = p_string.find_char('<', pos);
if (open_token_s == -1) {
r_err_out = "Unexpected end of data. No tags found.";
return false;
}
- int open_token_e = p_string.find(">", open_token_s);
+ int open_token_e = p_string.find_char('>', open_token_s);
pos = open_token_e;
String token = p_string.substr(open_token_s + 1, open_token_e - open_token_s - 1);
@@ -676,7 +676,7 @@ bool PList::load_string(const String &p_string, String &r_err_out) {
}
String value;
if (token[0] == '?' || token[0] == '!') { // Skip <?xml ... ?> and <!DOCTYPE ... >
- int end_token_e = p_string.find(">", open_token_s);
+ int end_token_e = p_string.find_char('>', open_token_s);
pos = end_token_e;
continue;
}
@@ -769,7 +769,7 @@ bool PList::load_string(const String &p_string, String &r_err_out) {
r_err_out = vformat("Mismatched <%s> tag.", token);
return false;
}
- int end_token_e = p_string.find(">", end_token_s);
+ int end_token_e = p_string.find_char('>', end_token_s);
pos = end_token_e;
String end_token = p_string.substr(end_token_s + 2, end_token_e - end_token_s - 2);
if (end_token != token) {
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index 3fea697d0b..1615f145db 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -295,13 +295,13 @@ Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_origin
load_paths_stack.push_back(original_path);
// Try all loaders and pick the first match for the type hint
- bool loader_found = false;
+ bool found = false;
Ref<Resource> res;
for (int i = 0; i < loader_count; i++) {
if (!loader[i]->recognize_path(p_path, p_type_hint)) {
continue;
}
- loader_found = true;
+ found = true;
res = loader[i]->load(p_path, original_path, r_error, p_use_sub_threads, r_progress, p_cache_mode);
if (!res.is_null()) {
break;
@@ -316,24 +316,15 @@ Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_origin
return res;
}
- if (!loader_found) {
- if (r_error) {
- *r_error = ERR_FILE_UNRECOGNIZED;
- }
- ERR_FAIL_V_MSG(Ref<Resource>(), vformat("No loader found for resource: %s (expected type: %s)", p_path, p_type_hint));
- }
+ ERR_FAIL_COND_V_MSG(found, Ref<Resource>(),
+ vformat("Failed loading resource: %s. Make sure resources have been imported by opening the project in the editor at least once.", p_path));
#ifdef TOOLS_ENABLED
Ref<FileAccess> file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
- if (!file_check->file_exists(p_path)) {
- if (r_error) {
- *r_error = ERR_FILE_NOT_FOUND;
- }
- ERR_FAIL_V_MSG(Ref<Resource>(), vformat("Resource file not found: %s (expected type: %s)", p_path, p_type_hint));
- }
+ ERR_FAIL_COND_V_MSG(!file_check->file_exists(p_path), Ref<Resource>(), vformat("Resource file not found: %s (expected type: %s)", p_path, p_type_hint));
#endif
- ERR_FAIL_V_MSG(Ref<Resource>(), vformat("Failed loading resource: %s. Make sure resources have been imported by opening the project in the editor at least once.", p_path));
+ ERR_FAIL_V_MSG(Ref<Resource>(), vformat("No loader found for resource: %s (expected type: %s)", p_path, p_type_hint));
}
// This implementation must allow re-entrancy for a task that started awaiting in a deeper stack frame.
@@ -1206,7 +1197,7 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem
int best_score = 0;
for (int i = 0; i < res_remaps.size(); i++) {
- int split = res_remaps[i].rfind(":");
+ int split = res_remaps[i].rfind_char(':');
if (split == -1) {
continue;
}
@@ -1498,11 +1489,11 @@ Vector<String> ResourceLoader::list_directory(const String &p_directory) {
}
} else {
if (d.ends_with(".import") || d.ends_with(".remap") || d.ends_with(".uid")) {
- d = d.substr(0, d.rfind("."));
+ d = d.substr(0, d.rfind_char('.'));
}
if (d.ends_with(".gdc")) {
- d = d.substr(0, d.rfind("."));
+ d = d.substr(0, d.rfind_char('.'));
d += ".gd";
}
diff --git a/core/io/resource_uid.cpp b/core/io/resource_uid.cpp
index c14121a53b..946bc524e5 100644
--- a/core/io/resource_uid.cpp
+++ b/core/io/resource_uid.cpp
@@ -34,6 +34,7 @@
#include "core/crypto/crypto_core.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
+#include "core/io/resource_loader.h"
// These constants are off by 1, causing the 'z' and '9' characters never to be used.
// This cannot be fixed without breaking compatibility; see GH-83843.
@@ -139,6 +140,21 @@ void ResourceUID::remove_id(ID p_id) {
unique_ids.erase(p_id);
}
+String ResourceUID::uid_to_path(const String &p_uid) {
+ return singleton->get_id_path(singleton->text_to_id(p_uid));
+}
+
+String ResourceUID::path_to_uid(const String &p_path) {
+ return singleton->id_to_text(ResourceLoader::get_resource_uid(p_path));
+}
+
+String ResourceUID::ensure_path(const String &p_uid_or_path) {
+ if (p_uid_or_path.begins_with("uid://")) {
+ return uid_to_path(p_uid_or_path);
+ }
+ return p_uid_or_path;
+}
+
Error ResourceUID::save_to_cache() {
String cache_file = get_cache_file();
if (!FileAccess::exists(cache_file)) {
diff --git a/core/io/resource_uid.h b/core/io/resource_uid.h
index e56b89f603..7b735d296a 100644
--- a/core/io/resource_uid.h
+++ b/core/io/resource_uid.h
@@ -73,6 +73,10 @@ public:
String get_id_path(ID p_id) const;
void remove_id(ID p_id);
+ static String uid_to_path(const String &p_uid);
+ static String path_to_uid(const String &p_path);
+ static String ensure_path(const String &p_uid_or_path);
+
Error load_from_cache(bool p_reset);
Error save_to_cache();
Error update_cache();
diff --git a/core/io/stream_peer.cpp b/core/io/stream_peer.cpp
index 3f1c468fb3..045904fb5d 100644
--- a/core/io/stream_peer.cpp
+++ b/core/io/stream_peer.cpp
@@ -178,6 +178,18 @@ void StreamPeer::put_64(int64_t p_val) {
put_data(buf, 8);
}
+void StreamPeer::put_half(float p_val) {
+ uint8_t buf[2];
+
+ encode_half(p_val, buf);
+ uint16_t *p16 = (uint16_t *)buf;
+ if (big_endian) {
+ *p16 = BSWAP16(*p16);
+ }
+
+ put_data(buf, 2);
+}
+
void StreamPeer::put_float(float p_val) {
uint8_t buf[4];
@@ -294,6 +306,18 @@ int64_t StreamPeer::get_64() {
return r;
}
+float StreamPeer::get_half() {
+ uint8_t buf[2];
+ get_data(buf, 2);
+
+ uint16_t *p16 = (uint16_t *)buf;
+ if (big_endian) {
+ *p16 = BSWAP16(*p16);
+ }
+
+ return decode_half(buf);
+}
+
float StreamPeer::get_float() {
uint8_t buf[4];
get_data(buf, 4);
@@ -385,6 +409,7 @@ void StreamPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("put_u32", "value"), &StreamPeer::put_u32);
ClassDB::bind_method(D_METHOD("put_64", "value"), &StreamPeer::put_64);
ClassDB::bind_method(D_METHOD("put_u64", "value"), &StreamPeer::put_u64);
+ ClassDB::bind_method(D_METHOD("put_half", "value"), &StreamPeer::put_half);
ClassDB::bind_method(D_METHOD("put_float", "value"), &StreamPeer::put_float);
ClassDB::bind_method(D_METHOD("put_double", "value"), &StreamPeer::put_double);
ClassDB::bind_method(D_METHOD("put_string", "value"), &StreamPeer::put_string);
@@ -399,6 +424,7 @@ void StreamPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_u32"), &StreamPeer::get_u32);
ClassDB::bind_method(D_METHOD("get_64"), &StreamPeer::get_64);
ClassDB::bind_method(D_METHOD("get_u64"), &StreamPeer::get_u64);
+ ClassDB::bind_method(D_METHOD("get_half"), &StreamPeer::get_half);
ClassDB::bind_method(D_METHOD("get_float"), &StreamPeer::get_float);
ClassDB::bind_method(D_METHOD("get_double"), &StreamPeer::get_double);
ClassDB::bind_method(D_METHOD("get_string", "bytes"), &StreamPeer::get_string, DEFVAL(-1));
diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h
index 29cdb82615..44bbfbf1d5 100644
--- a/core/io/stream_peer.h
+++ b/core/io/stream_peer.h
@@ -73,6 +73,7 @@ public:
void put_u32(uint32_t p_val);
void put_64(int64_t p_val);
void put_u64(uint64_t p_val);
+ void put_half(float p_val);
void put_float(float p_val);
void put_double(double p_val);
void put_string(const String &p_string);
@@ -87,6 +88,7 @@ public:
int32_t get_32();
uint64_t get_u64();
int64_t get_64();
+ float get_half();
float get_float();
double get_double();
String get_string(int p_bytes = -1);
diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp
index 7a11d06df6..1761d6fa23 100644
--- a/core/io/translation_loader_po.cpp
+++ b/core/io/translation_loader_po.cpp
@@ -108,7 +108,7 @@ Ref<Resource> TranslationLoaderPO::load_translation(Ref<FileAccess> f, Error *r_
// Record plural rule.
int p_start = config.find("Plural-Forms");
if (p_start != -1) {
- int p_end = config.find("\n", p_start);
+ int p_end = config.find_char('\n', p_start);
translation->set_plural_rule(config.substr(p_start, p_end - p_start));
}
} else {
@@ -224,7 +224,7 @@ Ref<Resource> TranslationLoaderPO::load_translation(Ref<FileAccess> f, Error *r_
// Record plural rule.
int p_start = config.find("Plural-Forms");
if (p_start != -1) {
- int p_end = config.find("\n", p_start);
+ int p_end = config.find_char('\n', p_start);
translation->set_plural_rule(config.substr(p_start, p_end - p_start));
plural_forms = translation->get_plural_forms();
}
@@ -324,7 +324,7 @@ Ref<Resource> TranslationLoaderPO::load_translation(Ref<FileAccess> f, Error *r_
Vector<String> configs = config.split("\n");
for (int i = 0; i < configs.size(); i++) {
String c = configs[i].strip_edges();
- int p = c.find(":");
+ int p = c.find_char(':');
if (p == -1) {
continue;
}
diff --git a/core/math/bvh_logic.inc b/core/math/bvh_logic.inc
index dd3b135bb5..aaa91bc9d3 100644
--- a/core/math/bvh_logic.inc
+++ b/core/math/bvh_logic.inc
@@ -1,4 +1,3 @@
-
// for slow incremental optimization, we will periodically remove each
// item from the tree and reinsert, to give it a chance to find a better position
void _logic_item_remove_and_reinsert(uint32_t p_ref_id) {
diff --git a/core/math/bvh_misc.inc b/core/math/bvh_misc.inc
index 9b35a1d36d..ef1261a759 100644
--- a/core/math/bvh_misc.inc
+++ b/core/math/bvh_misc.inc
@@ -1,4 +1,3 @@
-
int _handle_get_tree_id(BVHHandle p_handle) const {
if (USE_PAIRS) {
return _extra[p_handle.id()].tree_id;
diff --git a/core/math/bvh_structs.inc b/core/math/bvh_structs.inc
index d40c631ce2..6326cd63ef 100644
--- a/core/math/bvh_structs.inc
+++ b/core/math/bvh_structs.inc
@@ -1,4 +1,3 @@
-
public:
struct ItemRef {
uint32_t tnode_id; // -1 is invalid
diff --git a/core/math/projection.cpp b/core/math/projection.cpp
index d0ca7c5684..20638826a6 100644
--- a/core/math/projection.cpp
+++ b/core/math/projection.cpp
@@ -596,101 +596,229 @@ Projection Projection::inverse() const {
}
void Projection::invert() {
- int i, j, k;
- int pvt_i[4], pvt_j[4]; /* Locations of pivot matrix */
- real_t pvt_val; /* Value of current pivot element */
- real_t hold; /* Temporary storage */
- real_t determinant = 1.0f;
- for (k = 0; k < 4; k++) {
- /** Locate k'th pivot element **/
- pvt_val = columns[k][k]; /** Initialize for search **/
- pvt_i[k] = k;
- pvt_j[k] = k;
- for (i = k; i < 4; i++) {
- for (j = k; j < 4; j++) {
- if (Math::abs(columns[i][j]) > Math::abs(pvt_val)) {
- pvt_i[k] = i;
- pvt_j[k] = j;
- pvt_val = columns[i][j];
- }
- }
- }
-
- /** Product of pivots, gives determinant when finished **/
- determinant *= pvt_val;
- if (Math::is_zero_approx(determinant)) {
- return; /** Matrix is singular (zero determinant). **/
- }
-
- /** "Interchange" rows (with sign change stuff) **/
- i = pvt_i[k];
- if (i != k) { /** If rows are different **/
- for (j = 0; j < 4; j++) {
- hold = -columns[k][j];
- columns[k][j] = columns[i][j];
- columns[i][j] = hold;
- }
- }
-
- /** "Interchange" columns **/
- j = pvt_j[k];
- if (j != k) { /** If columns are different **/
- for (i = 0; i < 4; i++) {
- hold = -columns[i][k];
- columns[i][k] = columns[i][j];
- columns[i][j] = hold;
- }
- }
-
- /** Divide column by minus pivot value **/
- for (i = 0; i < 4; i++) {
- if (i != k) {
- columns[i][k] /= (-pvt_val);
- }
- }
-
- /** Reduce the matrix **/
- for (i = 0; i < 4; i++) {
- hold = columns[i][k];
- for (j = 0; j < 4; j++) {
- if (i != k && j != k) {
- columns[i][j] += hold * columns[k][j];
- }
- }
- }
-
- /** Divide row by pivot **/
- for (j = 0; j < 4; j++) {
- if (j != k) {
- columns[k][j] /= pvt_val;
- }
- }
-
- /** Replace pivot by reciprocal (at last we can touch it). **/
- columns[k][k] = 1.0 / pvt_val;
+ // Adapted from Mesa's `src/util/u_math.c` `util_invert_mat4x4`.
+ // MIT licensed. Copyright 2008 VMware, Inc. Authored by Jacques Leroy.
+ Projection temp;
+ real_t *out = (real_t *)temp.columns;
+ real_t *m = (real_t *)columns;
+
+ real_t wtmp[4][8];
+ real_t m0, m1, m2, m3, s;
+ real_t *r0, *r1, *r2, *r3;
+
+#define MAT(m, r, c) (m)[(c) * 4 + (r)]
+
+ r0 = wtmp[0];
+ r1 = wtmp[1];
+ r2 = wtmp[2];
+ r3 = wtmp[3];
+
+ r0[0] = MAT(m, 0, 0);
+ r0[1] = MAT(m, 0, 1);
+ r0[2] = MAT(m, 0, 2);
+ r0[3] = MAT(m, 0, 3);
+ r0[4] = 1.0;
+ r0[5] = 0.0;
+ r0[6] = 0.0;
+ r0[7] = 0.0;
+
+ r1[0] = MAT(m, 1, 0);
+ r1[1] = MAT(m, 1, 1);
+ r1[2] = MAT(m, 1, 2);
+ r1[3] = MAT(m, 1, 3);
+ r1[5] = 1.0;
+ r1[4] = 0.0;
+ r1[6] = 0.0;
+ r1[7] = 0.0;
+
+ r2[0] = MAT(m, 2, 0);
+ r2[1] = MAT(m, 2, 1);
+ r2[2] = MAT(m, 2, 2);
+ r2[3] = MAT(m, 2, 3);
+ r2[6] = 1.0;
+ r2[4] = 0.0;
+ r2[5] = 0.0;
+ r2[7] = 0.0;
+
+ r3[0] = MAT(m, 3, 0);
+ r3[1] = MAT(m, 3, 1);
+ r3[2] = MAT(m, 3, 2);
+ r3[3] = MAT(m, 3, 3);
+
+ r3[7] = 1.0;
+ r3[4] = 0.0;
+ r3[5] = 0.0;
+ r3[6] = 0.0;
+
+ /* choose pivot - or die */
+ if (Math::abs(r3[0]) > Math::abs(r2[0])) {
+ SWAP(r3, r2);
+ }
+ if (Math::abs(r2[0]) > Math::abs(r1[0])) {
+ SWAP(r2, r1);
+ }
+ if (Math::abs(r1[0]) > Math::abs(r0[0])) {
+ SWAP(r1, r0);
+ }
+ ERR_FAIL_COND(0.0 == r0[0]);
+
+ /* eliminate first variable */
+ m1 = r1[0] / r0[0];
+ m2 = r2[0] / r0[0];
+ m3 = r3[0] / r0[0];
+ s = r0[1];
+ r1[1] -= m1 * s;
+ r2[1] -= m2 * s;
+ r3[1] -= m3 * s;
+ s = r0[2];
+ r1[2] -= m1 * s;
+ r2[2] -= m2 * s;
+ r3[2] -= m3 * s;
+ s = r0[3];
+ r1[3] -= m1 * s;
+ r2[3] -= m2 * s;
+ r3[3] -= m3 * s;
+ s = r0[4];
+ if (s != 0.0) {
+ r1[4] -= m1 * s;
+ r2[4] -= m2 * s;
+ r3[4] -= m3 * s;
+ }
+ s = r0[5];
+ if (s != 0.0) {
+ r1[5] -= m1 * s;
+ r2[5] -= m2 * s;
+ r3[5] -= m3 * s;
+ }
+ s = r0[6];
+ if (s != 0.0) {
+ r1[6] -= m1 * s;
+ r2[6] -= m2 * s;
+ r3[6] -= m3 * s;
+ }
+ s = r0[7];
+ if (s != 0.0) {
+ r1[7] -= m1 * s;
+ r2[7] -= m2 * s;
+ r3[7] -= m3 * s;
}
- /* That was most of the work, one final pass of row/column interchange */
- /* to finish */
- for (k = 4 - 2; k >= 0; k--) { /* Don't need to work with 1 by 1 corner*/
- i = pvt_j[k]; /* Rows to swap correspond to pivot COLUMN */
- if (i != k) { /* If rows are different */
- for (j = 0; j < 4; j++) {
- hold = columns[k][j];
- columns[k][j] = -columns[i][j];
- columns[i][j] = hold;
- }
- }
+ /* choose pivot - or die */
+ if (Math::abs(r3[1]) > Math::abs(r2[1])) {
+ SWAP(r3, r2);
+ }
+ if (Math::abs(r2[1]) > Math::abs(r1[1])) {
+ SWAP(r2, r1);
+ }
+ ERR_FAIL_COND(0.0 == r1[1]);
+
+ /* eliminate second variable */
+ m2 = r2[1] / r1[1];
+ m3 = r3[1] / r1[1];
+ r2[2] -= m2 * r1[2];
+ r3[2] -= m3 * r1[2];
+ r2[3] -= m2 * r1[3];
+ r3[3] -= m3 * r1[3];
+ s = r1[4];
+ if (0.0 != s) {
+ r2[4] -= m2 * s;
+ r3[4] -= m3 * s;
+ }
+ s = r1[5];
+ if (0.0 != s) {
+ r2[5] -= m2 * s;
+ r3[5] -= m3 * s;
+ }
+ s = r1[6];
+ if (0.0 != s) {
+ r2[6] -= m2 * s;
+ r3[6] -= m3 * s;
+ }
+ s = r1[7];
+ if (0.0 != s) {
+ r2[7] -= m2 * s;
+ r3[7] -= m3 * s;
+ }
- j = pvt_i[k]; /* Columns to swap correspond to pivot ROW */
- if (j != k) { /* If columns are different */
- for (i = 0; i < 4; i++) {
- hold = columns[i][k];
- columns[i][k] = -columns[i][j];
- columns[i][j] = hold;
- }
- }
+ /* choose pivot - or die */
+ if (Math::abs(r3[2]) > Math::abs(r2[2])) {
+ SWAP(r3, r2);
}
+ ERR_FAIL_COND(0.0 == r2[2]);
+
+ /* eliminate third variable */
+ m3 = r3[2] / r2[2];
+ r3[3] -= m3 * r2[3];
+ r3[4] -= m3 * r2[4];
+ r3[5] -= m3 * r2[5];
+ r3[6] -= m3 * r2[6];
+ r3[7] -= m3 * r2[7];
+
+ /* last check */
+ ERR_FAIL_COND(0.0 == r3[3]);
+
+ s = 1.0 / r3[3]; /* now back substitute row 3 */
+ r3[4] *= s;
+ r3[5] *= s;
+ r3[6] *= s;
+ r3[7] *= s;
+
+ m2 = r2[3]; /* now back substitute row 2 */
+ s = 1.0 / r2[2];
+ r2[4] = s * (r2[4] - r3[4] * m2);
+ r2[5] = s * (r2[5] - r3[5] * m2);
+ r2[6] = s * (r2[6] - r3[6] * m2);
+ r2[7] = s * (r2[7] - r3[7] * m2);
+ m1 = r1[3];
+ r1[4] -= r3[4] * m1;
+ r1[5] -= r3[5] * m1;
+ r1[6] -= r3[6] * m1;
+ r1[7] -= r3[7] * m1;
+ m0 = r0[3];
+ r0[4] -= r3[4] * m0;
+ r0[5] -= r3[5] * m0;
+ r0[6] -= r3[6] * m0;
+ r0[7] -= r3[7] * m0;
+
+ m1 = r1[2]; /* now back substitute row 1 */
+ s = 1.0 / r1[1];
+ r1[4] = s * (r1[4] - r2[4] * m1);
+ r1[5] = s * (r1[5] - r2[5] * m1),
+ r1[6] = s * (r1[6] - r2[6] * m1);
+ r1[7] = s * (r1[7] - r2[7] * m1);
+ m0 = r0[2];
+ r0[4] -= r2[4] * m0;
+ r0[5] -= r2[5] * m0;
+ r0[6] -= r2[6] * m0;
+ r0[7] -= r2[7] * m0;
+
+ m0 = r0[1]; /* now back substitute row 0 */
+ s = 1.0 / r0[0];
+ r0[4] = s * (r0[4] - r1[4] * m0);
+ r0[5] = s * (r0[5] - r1[5] * m0),
+ r0[6] = s * (r0[6] - r1[6] * m0);
+ r0[7] = s * (r0[7] - r1[7] * m0);
+
+ MAT(out, 0, 0) = r0[4];
+ MAT(out, 0, 1) = r0[5];
+ MAT(out, 0, 2) = r0[6];
+ MAT(out, 0, 3) = r0[7];
+ MAT(out, 1, 0) = r1[4];
+ MAT(out, 1, 1) = r1[5];
+ MAT(out, 1, 2) = r1[6];
+ MAT(out, 1, 3) = r1[7];
+ MAT(out, 2, 0) = r2[4];
+ MAT(out, 2, 1) = r2[5];
+ MAT(out, 2, 2) = r2[6];
+ MAT(out, 2, 3) = r2[7];
+ MAT(out, 3, 0) = r3[4];
+ MAT(out, 3, 1) = r3[5];
+ MAT(out, 3, 2) = r3[6];
+ MAT(out, 3, 3) = r3[7];
+
+#undef MAT
+
+ *this = temp;
}
void Projection::flip_y() {
@@ -784,14 +912,10 @@ void Projection::set_light_atlas_rect(const Rect2 &p_rect) {
}
Projection::operator String() const {
- String str;
- for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- str += String((j > 0) ? ", " : "\n") + rtos(columns[i][j]);
- }
- }
-
- return str;
+ return "[X: " + columns[0].operator String() +
+ ", Y: " + columns[1].operator String() +
+ ", Z: " + columns[2].operator String() +
+ ", W: " + columns[3].operator String() + "]";
}
real_t Projection::get_aspect() const {
diff --git a/core/math/vector4.cpp b/core/math/vector4.cpp
index b6b914f36d..8ac2c4bf1f 100644
--- a/core/math/vector4.cpp
+++ b/core/math/vector4.cpp
@@ -213,7 +213,7 @@ Vector4 Vector4::clampf(real_t p_min, real_t p_max) const {
}
Vector4::operator String() const {
- return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")";
+ return "(" + String::num_real(x, true) + ", " + String::num_real(y, true) + ", " + String::num_real(z, true) + ", " + String::num_real(w, true) + ")";
}
static_assert(sizeof(Vector4) == 4 * sizeof(real_t));
diff --git a/core/object/object.h b/core/object/object.h
index 8f93b75bd8..11b94a7fbf 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -88,6 +88,7 @@ enum PropertyHint {
PROPERTY_HINT_LAYERS_AVOIDANCE,
PROPERTY_HINT_DICTIONARY_TYPE,
PROPERTY_HINT_TOOL_BUTTON,
+ PROPERTY_HINT_ONESHOT, ///< the property will be changed by self after setting, such as AudioStreamPlayer.playing, Particles.emitting.
PROPERTY_HINT_MAX,
};
diff --git a/core/object/worker_thread_pool.h b/core/object/worker_thread_pool.h
index 62296ac040..58e86e3e48 100644
--- a/core/object/worker_thread_pool.h
+++ b/core/object/worker_thread_pool.h
@@ -258,7 +258,13 @@ public:
bool is_group_task_completed(GroupID p_group) const;
void wait_for_group_task_completion(GroupID p_group);
- _FORCE_INLINE_ int get_thread_count() const { return threads.size(); }
+ _FORCE_INLINE_ int get_thread_count() const {
+#ifdef THREADS_ENABLED
+ return threads.size();
+#else
+ return 1;
+#endif
+ }
static WorkerThreadPool *get_singleton() { return singleton; }
static int get_thread_index();
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 59a0579ce3..1e9dbd2a18 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -536,9 +536,14 @@ bool OS::has_feature(const String &p_feature) {
return true;
}
- if (has_server_feature_callback && has_server_feature_callback(p_feature)) {
- return true;
+ if (has_server_feature_callback) {
+ return has_server_feature_callback(p_feature);
+ }
+#ifdef DEBUG_ENABLED
+ else if (is_stdout_verbose()) {
+ WARN_PRINT_ONCE("Server features cannot be checked before RenderingServer has been created. If you are checking a server feature, consider moving your OS::has_feature call after INITIALIZATION_LEVEL_SERVERS.");
}
+#endif
if (ProjectSettings::get_singleton()->has_custom_feature(p_feature)) {
return true;
diff --git a/core/os/os.h b/core/os/os.h
index 4bb177eb77..ffdb905aba 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -94,7 +94,15 @@ public:
enum RenderThreadMode {
RENDER_THREAD_UNSAFE,
RENDER_THREAD_SAFE,
- RENDER_SEPARATE_THREAD
+ RENDER_SEPARATE_THREAD,
+ };
+
+ enum StdHandleType {
+ STD_HANDLE_INVALID,
+ STD_HANDLE_CONSOLE,
+ STD_HANDLE_FILE,
+ STD_HANDLE_PIPE,
+ STD_HANDLE_UNKNOWN,
};
protected:
@@ -146,7 +154,12 @@ public:
void print_rich(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
void printerr(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
- virtual String get_stdin_string() = 0;
+ virtual String get_stdin_string(int64_t p_buffer_size = 1024) = 0;
+ virtual PackedByteArray get_stdin_buffer(int64_t p_buffer_size = 1024) = 0;
+
+ virtual StdHandleType get_stdin_type() const { return STD_HANDLE_UNKNOWN; }
+ virtual StdHandleType get_stdout_type() const { return STD_HANDLE_UNKNOWN; }
+ virtual StdHandleType get_stderr_type() const { return STD_HANDLE_UNKNOWN; }
virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) = 0; // Should return cryptographically-safe random bytes.
virtual String get_system_ca_certificates() { return ""; } // Concatenated certificates in PEM format.
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 3a578d01a6..685ba9d3d9 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -313,17 +313,28 @@ void register_core_settings() {
GLOBAL_DEF("threading/worker_pool/low_priority_thread_ratio", 0.3);
}
+void register_early_core_singletons() {
+ GDREGISTER_CLASS(core_bind::Engine);
+ Engine::get_singleton()->add_singleton(Engine::Singleton("Engine", core_bind::Engine::get_singleton()));
+
+ GDREGISTER_CLASS(ProjectSettings);
+ Engine::get_singleton()->add_singleton(Engine::Singleton("ProjectSettings", ProjectSettings::get_singleton()));
+
+ GDREGISTER_CLASS(core_bind::OS);
+ Engine::get_singleton()->add_singleton(Engine::Singleton("OS", core_bind::OS::get_singleton()));
+
+ GDREGISTER_CLASS(Time);
+ Engine::get_singleton()->add_singleton(Engine::Singleton("Time", Time::get_singleton()));
+}
+
void register_core_singletons() {
OS::get_singleton()->benchmark_begin_measure("Core", "Register Singletons");
- GDREGISTER_CLASS(ProjectSettings);
GDREGISTER_ABSTRACT_CLASS(IP);
GDREGISTER_CLASS(core_bind::Geometry2D);
GDREGISTER_CLASS(core_bind::Geometry3D);
GDREGISTER_CLASS(core_bind::ResourceLoader);
GDREGISTER_CLASS(core_bind::ResourceSaver);
- GDREGISTER_CLASS(core_bind::OS);
- GDREGISTER_CLASS(core_bind::Engine);
GDREGISTER_CLASS(core_bind::special::ClassDB);
GDREGISTER_CLASS(core_bind::Marshalls);
GDREGISTER_CLASS(TranslationServer);
@@ -331,23 +342,18 @@ void register_core_singletons() {
GDREGISTER_CLASS(InputMap);
GDREGISTER_CLASS(Expression);
GDREGISTER_CLASS(core_bind::EngineDebugger);
- GDREGISTER_CLASS(Time);
- Engine::get_singleton()->add_singleton(Engine::Singleton("ProjectSettings", ProjectSettings::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("IP", IP::get_singleton(), "IP"));
Engine::get_singleton()->add_singleton(Engine::Singleton("Geometry2D", core_bind::Geometry2D::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("Geometry3D", core_bind::Geometry3D::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("ResourceLoader", core_bind::ResourceLoader::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("ResourceSaver", core_bind::ResourceSaver::get_singleton()));
- Engine::get_singleton()->add_singleton(Engine::Singleton("OS", core_bind::OS::get_singleton()));
- Engine::get_singleton()->add_singleton(Engine::Singleton("Engine", core_bind::Engine::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("ClassDB", _classdb));
Engine::get_singleton()->add_singleton(Engine::Singleton("Marshalls", core_bind::Marshalls::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("TranslationServer", TranslationServer::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("Input", Input::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("InputMap", InputMap::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("EngineDebugger", core_bind::EngineDebugger::get_singleton()));
- Engine::get_singleton()->add_singleton(Engine::Singleton("Time", Time::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("GDExtensionManager", GDExtensionManager::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("ResourceUID", ResourceUID::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("WorkerThreadPool", worker_thread_pool));
diff --git a/core/register_core_types.h b/core/register_core_types.h
index eba569272e..b8db5c5d26 100644
--- a/core/register_core_types.h
+++ b/core/register_core_types.h
@@ -34,6 +34,7 @@
void register_core_types();
void register_core_settings();
void register_core_extensions();
+void register_early_core_singletons();
void register_core_singletons();
void unregister_core_types();
void unregister_core_extensions();
diff --git a/core/string/node_path.cpp b/core/string/node_path.cpp
index 3faf3bb0c5..40c81edf4c 100644
--- a/core/string/node_path.cpp
+++ b/core/string/node_path.cpp
@@ -407,7 +407,7 @@ NodePath::NodePath(const String &p_path) {
bool absolute = (path[0] == '/');
bool last_is_slash = true;
int slices = 0;
- int subpath_pos = path.find(":");
+ int subpath_pos = path.find_char(':');
if (subpath_pos != -1) {
int from = subpath_pos + 1;
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index 020949371f..d944135a70 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -80,8 +80,10 @@ void Translation::set_locale(const String &p_locale) {
if (Thread::is_main_thread()) {
_notify_translation_changed_if_applies();
} else {
- // Avoid calling non-thread-safe functions here.
- callable_mp(this, &Translation::_notify_translation_changed_if_applies).call_deferred();
+ // This has to happen on the main thread (bypassing the ResourceLoader per-thread call queue)
+ // because it interacts with the generally non-thread-safe window management, leading to
+ // different issues across platforms otherwise.
+ MessageQueue::get_main_singleton()->push_callable(callable_mp(this, &Translation::_notify_translation_changed_if_applies));
}
}
diff --git a/core/string/translation_po.cpp b/core/string/translation_po.cpp
index da79e472e7..7eb8a2afeb 100644
--- a/core/string/translation_po.cpp
+++ b/core/string/translation_po.cpp
@@ -227,11 +227,11 @@ void TranslationPO::set_plural_rule(const String &p_plural_rule) {
// Set plural_forms and plural_rule.
// p_plural_rule passed in has the form "Plural-Forms: nplurals=2; plural=(n >= 2);".
- int first_semi_col = p_plural_rule.find(";");
- plural_forms = p_plural_rule.substr(p_plural_rule.find("=") + 1, first_semi_col - (p_plural_rule.find("=") + 1)).to_int();
+ int first_semi_col = p_plural_rule.find_char(';');
+ plural_forms = p_plural_rule.substr(p_plural_rule.find_char('=') + 1, first_semi_col - (p_plural_rule.find_char('=') + 1)).to_int();
- int expression_start = p_plural_rule.find("=", first_semi_col) + 1;
- int second_semi_col = p_plural_rule.rfind(";");
+ int expression_start = p_plural_rule.find_char('=', first_semi_col) + 1;
+ int second_semi_col = p_plural_rule.rfind_char(';');
plural_rule = p_plural_rule.substr(expression_start, second_semi_col - expression_start).strip_edges();
// Setup the cache to make evaluating plural rule faster later on.
diff --git a/modules/text_server_adv/thorvg_bounds_iterator.cpp b/core/string/translation_server.compat.inc
index d273eef97f..11f508c654 100644
--- a/modules/text_server_adv/thorvg_bounds_iterator.cpp
+++ b/core/string/translation_server.compat.inc
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* thorvg_bounds_iterator.cpp */
+/* translation_server.compat.inc */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,43 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifdef GDEXTENSION
-// Headers for building as GDExtension plug-in.
+#ifndef DISABLE_DEPRECATED
-#include <godot_cpp/godot.hpp>
-
-using namespace godot;
-
-#elif defined(GODOT_MODULE)
-// Headers for building as built-in module.
-
-#include "core/typedefs.h"
-
-#include "modules/modules_enabled.gen.h" // For svg.
-#endif
-
-#ifdef MODULE_SVG_ENABLED
-
-#include "thorvg_bounds_iterator.h"
-
-#include <tvgIteratorAccessor.h>
-#include <tvgPaint.h>
-
-// This function uses private ThorVG API to get bounding box of top level children elements.
+String TranslationServer::_standardize_locale_bind_compat_98972(const String &p_locale) const {
+ return standardize_locale(p_locale, false);
+}
-void tvg_get_bounds(tvg::Picture *p_picture, float &r_min_x, float &r_min_y, float &r_max_x, float &r_max_y) {
- tvg::IteratorAccessor itrAccessor;
- if (tvg::Iterator *it = itrAccessor.iterator(p_picture)) {
- while (const tvg::Paint *child = it->next()) {
- float x = 0, y = 0, w = 0, h = 0;
- child->bounds(&x, &y, &w, &h, true);
- r_min_x = MIN(x, r_min_x);
- r_min_y = MIN(y, r_min_y);
- r_max_x = MAX(x + w, r_max_x);
- r_max_y = MAX(y + h, r_max_y);
- }
- delete (it);
- }
+void TranslationServer::_bind_compatibility_methods() {
+ ClassDB::bind_compatibility_method(D_METHOD("standardize_locale", "locale"), &TranslationServer::_standardize_locale_bind_compat_98972);
}
-#endif // MODULE_SVG_ENABLED
+#endif // DISABLE_DEPRECATED
diff --git a/core/string/translation_server.cpp b/core/string/translation_server.cpp
index 92b473b61f..3d49d482dd 100644
--- a/core/string/translation_server.cpp
+++ b/core/string/translation_server.cpp
@@ -29,6 +29,7 @@
/**************************************************************************/
#include "translation_server.h"
+#include "translation_server.compat.inc"
#include "core/config/project_settings.h"
#include "core/io/resource_loader.h"
@@ -118,36 +119,45 @@ void TranslationServer::init_locale_info() {
}
}
-String TranslationServer::standardize_locale(const String &p_locale) const {
- return _standardize_locale(p_locale, false);
+TranslationServer::Locale::operator String() const {
+ String out = language;
+ if (!script.is_empty()) {
+ out = out + "_" + script;
+ }
+ if (!country.is_empty()) {
+ out = out + "_" + country;
+ }
+ if (!variant.is_empty()) {
+ out = out + "_" + variant;
+ }
+ return out;
}
-String TranslationServer::_standardize_locale(const String &p_locale, bool p_add_defaults) const {
+TranslationServer::Locale::Locale(const TranslationServer &p_server, const String &p_locale, bool p_add_defaults) {
// Replaces '-' with '_' for macOS style locales.
String univ_locale = p_locale.replace("-", "_");
// Extract locale elements.
- String lang_name, script_name, country_name, variant_name;
Vector<String> locale_elements = univ_locale.get_slice("@", 0).split("_");
- lang_name = locale_elements[0];
+ language = locale_elements[0];
if (locale_elements.size() >= 2) {
if (locale_elements[1].length() == 4 && is_ascii_upper_case(locale_elements[1][0]) && is_ascii_lower_case(locale_elements[1][1]) && is_ascii_lower_case(locale_elements[1][2]) && is_ascii_lower_case(locale_elements[1][3])) {
- script_name = locale_elements[1];
+ script = locale_elements[1];
}
if (locale_elements[1].length() == 2 && is_ascii_upper_case(locale_elements[1][0]) && is_ascii_upper_case(locale_elements[1][1])) {
- country_name = locale_elements[1];
+ country = locale_elements[1];
}
}
if (locale_elements.size() >= 3) {
if (locale_elements[2].length() == 2 && is_ascii_upper_case(locale_elements[2][0]) && is_ascii_upper_case(locale_elements[2][1])) {
- country_name = locale_elements[2];
- } else if (variant_map.has(locale_elements[2].to_lower()) && variant_map[locale_elements[2].to_lower()] == lang_name) {
- variant_name = locale_elements[2].to_lower();
+ country = locale_elements[2];
+ } else if (p_server.variant_map.has(locale_elements[2].to_lower()) && p_server.variant_map[locale_elements[2].to_lower()] == language) {
+ variant = locale_elements[2].to_lower();
}
}
if (locale_elements.size() >= 4) {
- if (variant_map.has(locale_elements[3].to_lower()) && variant_map[locale_elements[3].to_lower()] == lang_name) {
- variant_name = locale_elements[3].to_lower();
+ if (p_server.variant_map.has(locale_elements[3].to_lower()) && p_server.variant_map[locale_elements[3].to_lower()] == language) {
+ variant = locale_elements[3].to_lower();
}
}
@@ -155,71 +165,62 @@ String TranslationServer::_standardize_locale(const String &p_locale, bool p_add
Vector<String> script_extra = univ_locale.get_slice("@", 1).split(";");
for (int i = 0; i < script_extra.size(); i++) {
if (script_extra[i].to_lower() == "cyrillic") {
- script_name = "Cyrl";
+ script = "Cyrl";
break;
} else if (script_extra[i].to_lower() == "latin") {
- script_name = "Latn";
+ script = "Latn";
break;
} else if (script_extra[i].to_lower() == "devanagari") {
- script_name = "Deva";
+ script = "Deva";
break;
- } else if (variant_map.has(script_extra[i].to_lower()) && variant_map[script_extra[i].to_lower()] == lang_name) {
- variant_name = script_extra[i].to_lower();
+ } else if (p_server.variant_map.has(script_extra[i].to_lower()) && p_server.variant_map[script_extra[i].to_lower()] == language) {
+ variant = script_extra[i].to_lower();
}
}
// Handles known non-ISO language names used e.g. on Windows.
- if (locale_rename_map.has(lang_name)) {
- lang_name = locale_rename_map[lang_name];
+ if (p_server.locale_rename_map.has(language)) {
+ language = p_server.locale_rename_map[language];
}
// Handle country renames.
- if (country_rename_map.has(country_name)) {
- country_name = country_rename_map[country_name];
+ if (p_server.country_rename_map.has(country)) {
+ country = p_server.country_rename_map[country];
}
// Remove unsupported script codes.
- if (!script_map.has(script_name)) {
- script_name = "";
+ if (!p_server.script_map.has(script)) {
+ script = "";
}
// Add script code base on language and country codes for some ambiguous cases.
if (p_add_defaults) {
- if (script_name.is_empty()) {
- for (int i = 0; i < locale_script_info.size(); i++) {
- const LocaleScriptInfo &info = locale_script_info[i];
- if (info.name == lang_name) {
- if (country_name.is_empty() || info.supported_countries.has(country_name)) {
- script_name = info.script;
+ if (script.is_empty()) {
+ for (int i = 0; i < p_server.locale_script_info.size(); i++) {
+ const LocaleScriptInfo &info = p_server.locale_script_info[i];
+ if (info.name == language) {
+ if (country.is_empty() || info.supported_countries.has(country)) {
+ script = info.script;
break;
}
}
}
}
- if (!script_name.is_empty() && country_name.is_empty()) {
+ if (!script.is_empty() && country.is_empty()) {
// Add conntry code based on script for some ambiguous cases.
- for (int i = 0; i < locale_script_info.size(); i++) {
- const LocaleScriptInfo &info = locale_script_info[i];
- if (info.name == lang_name && info.script == script_name) {
- country_name = info.default_country;
+ for (int i = 0; i < p_server.locale_script_info.size(); i++) {
+ const LocaleScriptInfo &info = p_server.locale_script_info[i];
+ if (info.name == language && info.script == script) {
+ country = info.default_country;
break;
}
}
}
}
+}
- // Combine results.
- String out = lang_name;
- if (!script_name.is_empty()) {
- out = out + "_" + script_name;
- }
- if (!country_name.is_empty()) {
- out = out + "_" + country_name;
- }
- if (!variant_name.is_empty()) {
- out = out + "_" + variant_name;
- }
- return out;
+String TranslationServer::standardize_locale(const String &p_locale, bool p_add_defaults) const {
+ return Locale(*this, p_locale, p_add_defaults).operator String();
}
int TranslationServer::compare_locales(const String &p_locale_a, const String &p_locale_b) const {
@@ -234,8 +235,8 @@ int TranslationServer::compare_locales(const String &p_locale_a, const String &p
return *cached_result;
}
- String locale_a = _standardize_locale(p_locale_a, true);
- String locale_b = _standardize_locale(p_locale_b, true);
+ Locale locale_a = Locale(*this, p_locale_a, true);
+ Locale locale_b = Locale(*this, p_locale_b, true);
if (locale_a == locale_b) {
// Exact match.
@@ -243,26 +244,41 @@ int TranslationServer::compare_locales(const String &p_locale_a, const String &p
return 10;
}
- Vector<String> locale_a_elements = locale_a.split("_");
- Vector<String> locale_b_elements = locale_b.split("_");
- if (locale_a_elements[0] != locale_b_elements[0]) {
+ if (locale_a.language != locale_b.language) {
// No match.
locale_compare_cache.insert(cache_key, 0);
return 0;
}
- // Matching language, both locales have extra parts.
- // Return number of matching elements.
- int matching_elements = 1;
- for (int i = 1; i < locale_a_elements.size(); i++) {
- for (int j = 1; j < locale_b_elements.size(); j++) {
- if (locale_a_elements[i] == locale_b_elements[j]) {
- matching_elements++;
- }
+ // Matching language, both locales have extra parts. Compare the
+ // remaining elements. If both elements are non-empty, check the
+ // match to increase or decrease the score. If either element or
+ // both are empty, leave the score as is.
+ int score = 5;
+ if (!locale_a.script.is_empty() && !locale_b.script.is_empty()) {
+ if (locale_a.script == locale_b.script) {
+ score++;
+ } else {
+ score--;
}
}
- locale_compare_cache.insert(cache_key, matching_elements);
- return matching_elements;
+ if (!locale_a.country.is_empty() && !locale_b.country.is_empty()) {
+ if (locale_a.country == locale_b.country) {
+ score++;
+ } else {
+ score--;
+ }
+ }
+ if (!locale_a.variant.is_empty() && !locale_b.variant.is_empty()) {
+ if (locale_a.variant == locale_b.variant) {
+ score++;
+ } else {
+ score--;
+ }
+ }
+
+ locale_compare_cache.insert(cache_key, score);
+ return score;
}
String TranslationServer::get_locale_name(const String &p_locale) const {
@@ -396,8 +412,6 @@ StringName TranslationServer::translate_plural(const StringName &p_message, cons
return main_domain->translate_plural(p_message, p_message_plural, p_n, p_context);
}
-TranslationServer *TranslationServer::singleton = nullptr;
-
bool TranslationServer::_load_translations(const String &p_from) {
if (ProjectSettings::get_singleton()->has_setting(p_from)) {
const Vector<String> &translation_names = GLOBAL_GET(p_from);
@@ -578,7 +592,7 @@ void TranslationServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tool_locale"), &TranslationServer::get_tool_locale);
ClassDB::bind_method(D_METHOD("compare_locales", "locale_a", "locale_b"), &TranslationServer::compare_locales);
- ClassDB::bind_method(D_METHOD("standardize_locale", "locale"), &TranslationServer::standardize_locale);
+ ClassDB::bind_method(D_METHOD("standardize_locale", "locale", "add_defaults"), &TranslationServer::standardize_locale, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_all_languages"), &TranslationServer::get_all_languages);
ClassDB::bind_method(D_METHOD("get_language_name", "language"), &TranslationServer::get_language_name);
diff --git a/core/string/translation_server.h b/core/string/translation_server.h
index 2438349a69..b6e4bba6e5 100644
--- a/core/string/translation_server.h
+++ b/core/string/translation_server.h
@@ -50,12 +50,16 @@ class TranslationServer : public Object {
bool enabled = true;
- static TranslationServer *singleton;
+ static inline TranslationServer *singleton = nullptr;
bool _load_translations(const String &p_from);
- String _standardize_locale(const String &p_locale, bool p_add_defaults) const;
static void _bind_methods();
+#ifndef DISABLE_DEPRECATED
+ String _standardize_locale_bind_compat_98972(const String &p_locale) const;
+ static void _bind_compatibility_methods();
+#endif
+
struct LocaleScriptInfo {
String name;
String script;
@@ -64,6 +68,24 @@ class TranslationServer : public Object {
};
static Vector<LocaleScriptInfo> locale_script_info;
+ struct Locale {
+ String language;
+ String script;
+ String country;
+ String variant;
+
+ bool operator==(const Locale &p_locale) const {
+ return (p_locale.language == language) &&
+ (p_locale.script == script) &&
+ (p_locale.country == country) &&
+ (p_locale.variant == variant);
+ }
+
+ operator String() const;
+
+ Locale(const TranslationServer &p_server, const String &p_locale, bool p_add_defaults);
+ };
+
static HashMap<String, String> language_map;
static HashMap<String, String> script_map;
static HashMap<String, String> locale_rename_map;
@@ -111,7 +133,7 @@ public:
void set_pseudolocalization_enabled(bool p_enabled);
void reload_pseudolocalization();
- String standardize_locale(const String &p_locale) const;
+ String standardize_locale(const String &p_locale, bool p_add_defaults = false) const;
int compare_locales(const String &p_locale_a, const String &p_locale_b) const;
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 521dfe0b8c..9e99fc3b2f 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -246,27 +246,27 @@ Error String::parse_url(String &r_scheme, String &r_host, int &r_port, String &r
base = base.substr(pos + 3, base.length() - pos - 3);
}
}
- pos = base.find("#");
+ pos = base.find_char('#');
// Fragment
if (pos != -1) {
r_fragment = base.substr(pos + 1);
base = base.substr(0, pos);
}
- pos = base.find("/");
+ pos = base.find_char('/');
// Path
if (pos != -1) {
r_path = base.substr(pos, base.length() - pos);
base = base.substr(0, pos);
}
// Host
- pos = base.find("@");
+ pos = base.find_char('@');
if (pos != -1) {
// Strip credentials
base = base.substr(pos + 1, base.length() - pos - 1);
}
if (base.begins_with("[")) {
// Literal IPv6
- pos = base.rfind("]");
+ pos = base.rfind_char(']');
if (pos == -1) {
return ERR_INVALID_PARAMETER;
}
@@ -277,7 +277,7 @@ Error String::parse_url(String &r_scheme, String &r_host, int &r_port, String &r
if (base.get_slice_count(":") > 2) {
return ERR_INVALID_PARAMETER;
}
- pos = base.rfind(":");
+ pos = base.rfind_char(':');
if (pos == -1) {
r_host = base;
base = "";
@@ -2641,7 +2641,7 @@ int64_t String::to_int() const {
return 0;
}
- int to = (find(".") >= 0) ? find(".") : length();
+ int to = (find_char('.') >= 0) ? find_char('.') : length();
int64_t integer = 0;
int64_t sign = 1;
@@ -4580,7 +4580,7 @@ String String::simplify_path() const {
if (p == -1) {
p = s.find(":\\");
}
- if (p != -1 && p < s.find("/")) {
+ if (p != -1 && p < s.find_char('/')) {
drive = s.substr(0, p + 2);
s = s.substr(p + 2);
}
@@ -5025,7 +5025,7 @@ String String::xml_unescape() const {
String String::pad_decimals(int p_digits) const {
String s = *this;
- int c = s.find(".");
+ int c = s.find_char('.');
if (c == -1) {
if (p_digits <= 0) {
@@ -5049,7 +5049,7 @@ String String::pad_decimals(int p_digits) const {
String String::pad_zeros(int p_digits) const {
String s = *this;
- int end = s.find(".");
+ int end = s.find_char('.');
if (end == -1) {
end = s.length();
@@ -5316,7 +5316,7 @@ String String::validate_filename() const {
}
bool String::is_valid_ip_address() const {
- if (find(":") >= 0) {
+ if (find_char(':') >= 0) {
Vector<String> ip = split(":");
for (int i = 0; i < ip.size(); i++) {
const String &n = ip[i];
@@ -5386,13 +5386,13 @@ String String::get_base_dir() const {
// Windows UNC network share path.
if (end == 0) {
if (is_network_share_path()) {
- basepos = find("/", 2);
+ basepos = find_char('/', 2);
if (basepos == -1) {
- basepos = find("\\", 2);
+ basepos = find_char('\\', 2);
}
- int servpos = find("/", basepos + 1);
+ int servpos = find_char('/', basepos + 1);
if (servpos == -1) {
- servpos = find("\\", basepos + 1);
+ servpos = find_char('\\', basepos + 1);
}
if (servpos != -1) {
end = servpos + 1;
@@ -5416,7 +5416,7 @@ String String::get_base_dir() const {
rs = *this;
}
- int sep = MAX(rs.rfind("/"), rs.rfind("\\"));
+ int sep = MAX(rs.rfind_char('/'), rs.rfind_char('\\'));
if (sep == -1) {
return base;
}
@@ -5425,7 +5425,7 @@ String String::get_base_dir() const {
}
String String::get_file() const {
- int sep = MAX(rfind("/"), rfind("\\"));
+ int sep = MAX(rfind_char('/'), rfind_char('\\'));
if (sep == -1) {
return *this;
}
@@ -5434,8 +5434,8 @@ String String::get_file() const {
}
String String::get_extension() const {
- int pos = rfind(".");
- if (pos < 0 || pos < MAX(rfind("/"), rfind("\\"))) {
+ int pos = rfind_char('.');
+ if (pos < 0 || pos < MAX(rfind_char('/'), rfind_char('\\'))) {
return "";
}
@@ -5533,8 +5533,8 @@ String String::validate_node_name() const {
}
String String::get_basename() const {
- int pos = rfind(".");
- if (pos < 0 || pos < MAX(rfind("/"), rfind("\\"))) {
+ int pos = rfind_char('.');
+ if (pos < 0 || pos < MAX(rfind_char('/'), rfind_char('\\'))) {
return *this;
}
diff --git a/core/templates/a_hash_map.h b/core/templates/a_hash_map.h
index 29983ea268..6e3a978d50 100644
--- a/core/templates/a_hash_map.h
+++ b/core/templates/a_hash_map.h
@@ -622,10 +622,11 @@ public:
}
// Inserts an element without checking if it already exists.
- void insert_new(const TKey &p_key, const TValue &p_value) {
+ Iterator insert_new(const TKey &p_key, const TValue &p_value) {
DEV_ASSERT(!has(p_key));
uint32_t hash = _hash(p_key);
- _insert_element(p_key, p_value, hash);
+ uint32_t pos = _insert_element(p_key, p_value, hash);
+ return Iterator(elements + pos, elements, elements + num_elements);
}
/* Array methods. */
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index 5ce90cd8ff..ddeea27118 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -206,19 +206,17 @@ int Callable::get_bound_arguments_count() const {
}
}
-void Callable::get_bound_arguments_ref(Vector<Variant> &r_arguments, int &r_argcount) const {
+void Callable::get_bound_arguments_ref(Vector<Variant> &r_arguments) const {
if (!is_null() && is_custom()) {
- custom->get_bound_arguments(r_arguments, r_argcount);
+ custom->get_bound_arguments(r_arguments);
} else {
r_arguments.clear();
- r_argcount = 0;
}
}
Array Callable::get_bound_arguments() const {
Vector<Variant> arr;
- int ac;
- get_bound_arguments_ref(arr, ac);
+ get_bound_arguments_ref(arr);
Array ret;
ret.resize(arr.size());
for (int i = 0; i < arr.size(); i++) {
@@ -227,6 +225,14 @@ Array Callable::get_bound_arguments() const {
return ret;
}
+int Callable::get_unbound_arguments_count() const {
+ if (!is_null() && is_custom()) {
+ return custom->get_unbound_arguments_count();
+ } else {
+ return 0;
+ }
+}
+
CallableCustom *Callable::get_custom() const {
ERR_FAIL_COND_V_MSG(!is_custom(), nullptr,
vformat("Can't get custom on non-CallableCustom \"%s\".", operator String()));
@@ -464,9 +470,12 @@ int CallableCustom::get_bound_arguments_count() const {
return 0;
}
-void CallableCustom::get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const {
- r_arguments = Vector<Variant>();
- r_argcount = 0;
+void CallableCustom::get_bound_arguments(Vector<Variant> &r_arguments) const {
+ r_arguments.clear();
+}
+
+int CallableCustom::get_unbound_arguments_count() const {
+ return 0;
}
CallableCustom::CallableCustom() {
diff --git a/core/variant/callable.h b/core/variant/callable.h
index e3c940a0e5..e76b888ac2 100644
--- a/core/variant/callable.h
+++ b/core/variant/callable.h
@@ -111,8 +111,9 @@ public:
CallableCustom *get_custom() const;
int get_argument_count(bool *r_is_valid = nullptr) const;
int get_bound_arguments_count() const;
- void get_bound_arguments_ref(Vector<Variant> &r_arguments, int &r_argcount) const; // Internal engine use, the exposed one is below.
+ void get_bound_arguments_ref(Vector<Variant> &r_arguments) const; // Internal engine use, the exposed one is below.
Array get_bound_arguments() const;
+ int get_unbound_arguments_count() const;
uint32_t hash() const;
@@ -158,7 +159,8 @@ public:
virtual const Callable *get_base_comparator() const;
virtual int get_argument_count(bool &r_is_valid) const;
virtual int get_bound_arguments_count() const;
- virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const;
+ virtual void get_bound_arguments(Vector<Variant> &r_arguments) const;
+ virtual int get_unbound_arguments_count() const;
CallableCustom();
virtual ~CallableCustom() {}
diff --git a/core/variant/callable_bind.cpp b/core/variant/callable_bind.cpp
index afb889551e..43cac263c1 100644
--- a/core/variant/callable_bind.cpp
+++ b/core/variant/callable_bind.cpp
@@ -100,44 +100,42 @@ int CallableCustomBind::get_argument_count(bool &r_is_valid) const {
}
int CallableCustomBind::get_bound_arguments_count() const {
- return callable.get_bound_arguments_count() + binds.size();
+ return callable.get_bound_arguments_count() + MAX(0, binds.size() - callable.get_unbound_arguments_count());
}
-void CallableCustomBind::get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const {
- Vector<Variant> sub_args;
- int sub_count;
- callable.get_bound_arguments_ref(sub_args, sub_count);
+void CallableCustomBind::get_bound_arguments(Vector<Variant> &r_arguments) const {
+ Vector<Variant> sub_bound_args;
+ callable.get_bound_arguments_ref(sub_bound_args);
+ int sub_bound_count = sub_bound_args.size();
- if (sub_count == 0) {
+ int sub_unbound_count = callable.get_unbound_arguments_count();
+
+ if (sub_bound_count == 0 && sub_unbound_count == 0) {
r_arguments = binds;
- r_argcount = binds.size();
return;
}
- int new_count = sub_count + binds.size();
- r_argcount = new_count;
+ int added_count = MAX(0, binds.size() - sub_unbound_count);
+ int new_count = sub_bound_count + added_count;
- if (new_count <= 0) {
- // Removed more arguments than it adds.
- r_arguments = Vector<Variant>();
+ if (added_count <= 0) {
+ // All added arguments are consumed by `sub_unbound_count`.
+ r_arguments = sub_bound_args;
return;
}
r_arguments.resize(new_count);
-
- if (sub_count > 0) {
- for (int i = 0; i < sub_count; i++) {
- r_arguments.write[i] = sub_args[i];
- }
- for (int i = 0; i < binds.size(); i++) {
- r_arguments.write[i + sub_count] = binds[i];
- }
- r_argcount = new_count;
- } else {
- for (int i = 0; i < binds.size() + sub_count; i++) {
- r_arguments.write[i] = binds[i - sub_count];
- }
+ Variant *args = r_arguments.ptrw();
+ for (int i = 0; i < added_count; i++) {
+ args[i] = binds[i];
}
+ for (int i = 0; i < sub_bound_count; i++) {
+ args[i + added_count] = sub_bound_args[i];
+ }
+}
+
+int CallableCustomBind::get_unbound_arguments_count() const {
+ return MAX(0, callable.get_unbound_arguments_count() - binds.size());
}
void CallableCustomBind::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
@@ -242,22 +240,15 @@ int CallableCustomUnbind::get_argument_count(bool &r_is_valid) const {
}
int CallableCustomUnbind::get_bound_arguments_count() const {
- return callable.get_bound_arguments_count() - argcount;
+ return callable.get_bound_arguments_count();
}
-void CallableCustomUnbind::get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const {
- Vector<Variant> sub_args;
- int sub_count;
- callable.get_bound_arguments_ref(sub_args, sub_count);
-
- r_argcount = sub_args.size() - argcount;
+void CallableCustomUnbind::get_bound_arguments(Vector<Variant> &r_arguments) const {
+ callable.get_bound_arguments_ref(r_arguments);
+}
- if (argcount >= sub_args.size()) {
- r_arguments = Vector<Variant>();
- } else {
- sub_args.resize(sub_args.size() - argcount);
- r_arguments = sub_args;
- }
+int CallableCustomUnbind::get_unbound_arguments_count() const {
+ return callable.get_unbound_arguments_count() + argcount;
}
void CallableCustomUnbind::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
diff --git a/core/variant/callable_bind.h b/core/variant/callable_bind.h
index 43cebb45f0..1346277197 100644
--- a/core/variant/callable_bind.h
+++ b/core/variant/callable_bind.h
@@ -55,7 +55,8 @@ public:
virtual const Callable *get_base_comparator() const override;
virtual int get_argument_count(bool &r_is_valid) const override;
virtual int get_bound_arguments_count() const override;
- virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const override;
+ virtual void get_bound_arguments(Vector<Variant> &r_arguments) const override;
+ virtual int get_unbound_arguments_count() const override;
Callable get_callable() { return callable; }
Vector<Variant> get_binds() { return binds; }
@@ -84,7 +85,8 @@ public:
virtual const Callable *get_base_comparator() const override;
virtual int get_argument_count(bool &r_is_valid) const override;
virtual int get_bound_arguments_count() const override;
- virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const override;
+ virtual void get_bound_arguments(Vector<Variant> &r_arguments) const override;
+ virtual int get_unbound_arguments_count() const override;
Callable get_callable() { return callable; }
int get_unbinds() { return argcount; }
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index 54936eb8a2..8aca56c1d5 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -3560,9 +3560,6 @@ bool Variant::is_ref_counted() const {
return type == OBJECT && _get_obj().id.is_ref_counted();
}
-void Variant::static_assign(const Variant &p_variant) {
-}
-
bool Variant::is_type_shared(Variant::Type p_type) {
switch (p_type) {
case OBJECT:
@@ -3664,18 +3661,20 @@ String Variant::get_call_error_text(Object *p_base, const StringName &p_method,
String Variant::get_callable_error_text(const Callable &p_callable, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce) {
Vector<Variant> binds;
- int args_bound;
- p_callable.get_bound_arguments_ref(binds, args_bound);
- if (args_bound <= 0) {
- return get_call_error_text(p_callable.get_object(), p_callable.get_method(), p_argptrs, MAX(0, p_argcount + args_bound), ce);
+ p_callable.get_bound_arguments_ref(binds);
+
+ int args_unbound = p_callable.get_unbound_arguments_count();
+
+ if (p_argcount - args_unbound < 0) {
+ return "Callable unbinds " + itos(args_unbound) + " arguments, but called with " + itos(p_argcount);
} else {
Vector<const Variant *> argptrs;
- argptrs.resize(p_argcount + binds.size());
- for (int i = 0; i < p_argcount; i++) {
+ argptrs.resize(p_argcount - args_unbound + binds.size());
+ for (int i = 0; i < p_argcount - args_unbound; i++) {
argptrs.write[i] = p_argptrs[i];
}
for (int i = 0; i < binds.size(); i++) {
- argptrs.write[i + p_argcount] = &binds[i];
+ argptrs.write[i + p_argcount - args_unbound] = &binds[i];
}
return get_call_error_text(p_callable.get_object(), p_callable.get_method(), (const Variant **)argptrs.ptr(), argptrs.size(), ce);
}
diff --git a/core/variant/variant.h b/core/variant/variant.h
index 9702c67a37..babd2cf084 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -792,7 +792,6 @@ public:
String stringify(int recursion_count = 0) const;
String to_json_string() const;
- void static_assign(const Variant &p_variant);
static void get_constants_for_type(Variant::Type p_type, List<StringName> *p_constants);
static int get_constants_count_for_type(Variant::Type p_type);
static bool has_constant(Variant::Type p_type, const StringName &p_value);
@@ -801,6 +800,8 @@ public:
static void get_enums_for_type(Variant::Type p_type, List<StringName> *p_enums);
static void get_enumerations_for_enum(Variant::Type p_type, const StringName &p_enum_name, List<StringName> *p_enumerations);
static int get_enum_value(Variant::Type p_type, const StringName &p_enum_name, const StringName &p_enumeration, bool *r_valid = nullptr);
+ static bool has_enum(Variant::Type p_type, const StringName &p_enum_name);
+ static StringName get_enum_for_enumeration(Variant::Type p_type, const StringName &p_enumeration);
typedef String (*ObjectDeConstruct)(const Variant &p_object, void *ud);
typedef void (*ObjectConstruct)(const String &p_text, void *ud, Variant &r_value);
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 29e11462c9..d612cb9cea 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1091,6 +1091,11 @@ struct _VariantCall {
static ConstantData *constant_data;
static void add_constant(int p_type, const StringName &p_constant_name, int64_t p_constant_value) {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND(constant_data[p_type].value.has(p_constant_name));
+ ERR_FAIL_COND(enum_data[p_type].value.has(p_constant_name));
+ ERR_FAIL_COND(enum_data[p_type].value_to_enum.has(p_constant_name));
+#endif
constant_data[p_type].value[p_constant_name] = p_constant_value;
#ifdef DEBUG_ENABLED
constant_data[p_type].value_ordered.push_back(p_constant_name);
@@ -1106,12 +1111,19 @@ struct _VariantCall {
struct EnumData {
HashMap<StringName, HashMap<StringName, int>> value;
+ HashMap<StringName, StringName> value_to_enum;
};
static EnumData *enum_data;
static void add_enum_constant(int p_type, const StringName &p_enum_type_name, const StringName &p_enumeration_name, int p_enum_value) {
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND(constant_data[p_type].value.has(p_enumeration_name));
+ ERR_FAIL_COND(enum_data[p_type].value.has(p_enumeration_name));
+ ERR_FAIL_COND(enum_data[p_type].value_to_enum.has(p_enumeration_name));
+#endif
enum_data[p_type].value[p_enum_type_name][p_enumeration_name] = p_enum_value;
+ enum_data[p_type].value_to_enum[p_enumeration_name] = p_enum_type_name;
}
};
@@ -1561,6 +1573,23 @@ int Variant::get_enum_value(Variant::Type p_type, const StringName &p_enum_name,
return V->value;
}
+bool Variant::has_enum(Variant::Type p_type, const StringName &p_enum_name) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
+
+ _VariantCall::EnumData &enum_data = _VariantCall::enum_data[p_type];
+
+ return enum_data.value.has(p_enum_name);
+}
+
+StringName Variant::get_enum_for_enumeration(Variant::Type p_type, const StringName &p_enumeration) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, StringName());
+
+ _VariantCall::EnumData &enum_data = _VariantCall::enum_data[p_type];
+
+ const StringName *enum_name = enum_data.value_to_enum.getptr(p_enumeration);
+ return (enum_name == nullptr) ? StringName() : *enum_name;
+}
+
#ifdef DEBUG_METHODS_ENABLED
#define bind_method(m_type, m_method, m_arg_names, m_default_args) \
METHOD_CLASS(m_type, m_method, &m_type::m_method); \
@@ -2116,6 +2145,7 @@ static void _register_variant_builtin_methods_misc() {
bind_function(Callable, get_argument_count, _VariantCall::func_Callable_get_argument_count, sarray(), varray());
bind_method(Callable, get_bound_arguments_count, sarray(), varray());
bind_method(Callable, get_bound_arguments, sarray(), varray());
+ bind_method(Callable, get_unbound_arguments_count, sarray(), varray());
bind_method(Callable, hash, sarray(), varray());
bind_method(Callable, bindv, sarray("arguments"), varray());
bind_method(Callable, unbind, sarray("argcount"), varray());
@@ -2659,10 +2689,6 @@ static void _register_variant_builtin_constants() {
_VariantCall::add_variant_constant(Variant::COLOR, Color::get_named_color_name(i), Color::get_named_color(i));
}
- _VariantCall::add_constant(Variant::VECTOR3, "AXIS_X", Vector3::AXIS_X);
- _VariantCall::add_constant(Variant::VECTOR3, "AXIS_Y", Vector3::AXIS_Y);
- _VariantCall::add_constant(Variant::VECTOR3, "AXIS_Z", Vector3::AXIS_Z);
-
_VariantCall::add_enum_constant(Variant::VECTOR3, "Axis", "AXIS_X", Vector3::AXIS_X);
_VariantCall::add_enum_constant(Variant::VECTOR3, "Axis", "AXIS_Y", Vector3::AXIS_Y);
_VariantCall::add_enum_constant(Variant::VECTOR3, "Axis", "AXIS_Z", Vector3::AXIS_Z);
@@ -2684,32 +2710,19 @@ static void _register_variant_builtin_constants() {
_VariantCall::add_variant_constant(Variant::VECTOR3, "MODEL_FRONT", Vector3(0, 0, 1));
_VariantCall::add_variant_constant(Variant::VECTOR3, "MODEL_REAR", Vector3(0, 0, -1));
- _VariantCall::add_constant(Variant::VECTOR4, "AXIS_X", Vector4::AXIS_X);
- _VariantCall::add_constant(Variant::VECTOR4, "AXIS_Y", Vector4::AXIS_Y);
- _VariantCall::add_constant(Variant::VECTOR4, "AXIS_Z", Vector4::AXIS_Z);
- _VariantCall::add_constant(Variant::VECTOR4, "AXIS_W", Vector4::AXIS_W);
-
_VariantCall::add_enum_constant(Variant::VECTOR4, "Axis", "AXIS_X", Vector4::AXIS_X);
_VariantCall::add_enum_constant(Variant::VECTOR4, "Axis", "AXIS_Y", Vector4::AXIS_Y);
_VariantCall::add_enum_constant(Variant::VECTOR4, "Axis", "AXIS_Z", Vector4::AXIS_Z);
_VariantCall::add_enum_constant(Variant::VECTOR4, "Axis", "AXIS_W", Vector4::AXIS_W);
+
_VariantCall::add_variant_constant(Variant::VECTOR4, "ZERO", Vector4(0, 0, 0, 0));
_VariantCall::add_variant_constant(Variant::VECTOR4, "ONE", Vector4(1, 1, 1, 1));
_VariantCall::add_variant_constant(Variant::VECTOR4, "INF", Vector4(INFINITY, INFINITY, INFINITY, INFINITY));
- _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_X", Vector3i::AXIS_X);
- _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Y", Vector3i::AXIS_Y);
- _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Z", Vector3i::AXIS_Z);
-
_VariantCall::add_enum_constant(Variant::VECTOR3I, "Axis", "AXIS_X", Vector3i::AXIS_X);
_VariantCall::add_enum_constant(Variant::VECTOR3I, "Axis", "AXIS_Y", Vector3i::AXIS_Y);
_VariantCall::add_enum_constant(Variant::VECTOR3I, "Axis", "AXIS_Z", Vector3i::AXIS_Z);
- _VariantCall::add_constant(Variant::VECTOR4I, "AXIS_X", Vector4i::AXIS_X);
- _VariantCall::add_constant(Variant::VECTOR4I, "AXIS_Y", Vector4i::AXIS_Y);
- _VariantCall::add_constant(Variant::VECTOR4I, "AXIS_Z", Vector4i::AXIS_Z);
- _VariantCall::add_constant(Variant::VECTOR4I, "AXIS_W", Vector4i::AXIS_W);
-
_VariantCall::add_enum_constant(Variant::VECTOR4I, "Axis", "AXIS_X", Vector4i::AXIS_X);
_VariantCall::add_enum_constant(Variant::VECTOR4I, "Axis", "AXIS_Y", Vector4i::AXIS_Y);
_VariantCall::add_enum_constant(Variant::VECTOR4I, "Axis", "AXIS_Z", Vector4i::AXIS_Z);
@@ -2731,15 +2744,9 @@ static void _register_variant_builtin_constants() {
_VariantCall::add_variant_constant(Variant::VECTOR3I, "FORWARD", Vector3i(0, 0, -1));
_VariantCall::add_variant_constant(Variant::VECTOR3I, "BACK", Vector3i(0, 0, 1));
- _VariantCall::add_constant(Variant::VECTOR2, "AXIS_X", Vector2::AXIS_X);
- _VariantCall::add_constant(Variant::VECTOR2, "AXIS_Y", Vector2::AXIS_Y);
-
_VariantCall::add_enum_constant(Variant::VECTOR2, "Axis", "AXIS_X", Vector2::AXIS_X);
_VariantCall::add_enum_constant(Variant::VECTOR2, "Axis", "AXIS_Y", Vector2::AXIS_Y);
- _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_X", Vector2i::AXIS_X);
- _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_Y", Vector2i::AXIS_Y);
-
_VariantCall::add_enum_constant(Variant::VECTOR2I, "Axis", "AXIS_X", Vector2i::AXIS_X);
_VariantCall::add_enum_constant(Variant::VECTOR2I, "Axis", "AXIS_Y", Vector2i::AXIS_Y);
@@ -2788,13 +2795,6 @@ static void _register_variant_builtin_constants() {
_VariantCall::add_variant_constant(Variant::QUATERNION, "IDENTITY", Quaternion(0, 0, 0, 1));
- _VariantCall::add_constant(Variant::PROJECTION, "PLANE_NEAR", Projection::PLANE_NEAR);
- _VariantCall::add_constant(Variant::PROJECTION, "PLANE_FAR", Projection::PLANE_FAR);
- _VariantCall::add_constant(Variant::PROJECTION, "PLANE_LEFT", Projection::PLANE_LEFT);
- _VariantCall::add_constant(Variant::PROJECTION, "PLANE_TOP", Projection::PLANE_TOP);
- _VariantCall::add_constant(Variant::PROJECTION, "PLANE_RIGHT", Projection::PLANE_RIGHT);
- _VariantCall::add_constant(Variant::PROJECTION, "PLANE_BOTTOM", Projection::PLANE_BOTTOM);
-
_VariantCall::add_enum_constant(Variant::PROJECTION, "Planes", "PLANE_NEAR", Projection::PLANE_NEAR);
_VariantCall::add_enum_constant(Variant::PROJECTION, "Planes", "PLANE_FAR", Projection::PLANE_FAR);
_VariantCall::add_enum_constant(Variant::PROJECTION, "Planes", "PLANE_LEFT", Projection::PLANE_LEFT);
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 66f15f7494..182848db71 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -991,8 +991,8 @@
[codeblock]
var a = rand_from_seed(4)
- print(a[0]) # Prints 2879024997
- print(a[1]) # Prints 4
+ print(a[0]) # Prints 2879024997
+ print(a[1]) # Prints 4
[/codeblock]
</description>
</method>
@@ -2143,49 +2143,49 @@
Space key.
</constant>
<constant name="KEY_EXCLAM" value="33" enum="Key">
- ! key.
+ Exclamation mark ([code]![/code]) key.
</constant>
<constant name="KEY_QUOTEDBL" value="34" enum="Key">
- " key.
+ Double quotation mark ([code]"[/code]) key.
</constant>
- <constant name="KEY_NUMBERSIGN" value="35" enum="Key">
- # key.
+ <constant name="KEY_NUMBERSIGN" value="35" enum="Key" keywords="pound, hash">
+ Number sign or [i]hash[/i] ([code]#[/code]) key.
</constant>
<constant name="KEY_DOLLAR" value="36" enum="Key">
- $ key.
+ Dollar sign ([code]$[/code]) key.
</constant>
<constant name="KEY_PERCENT" value="37" enum="Key">
- % key.
+ Percent sign ([code]%[/code]) key.
</constant>
<constant name="KEY_AMPERSAND" value="38" enum="Key">
- &amp; key.
+ Ampersand ([code]&amp;[/code]) key.
</constant>
<constant name="KEY_APOSTROPHE" value="39" enum="Key">
- ' key.
+ Apostrophe ([code]'[/code]) key.
</constant>
- <constant name="KEY_PARENLEFT" value="40" enum="Key">
- ( key.
+ <constant name="KEY_PARENLEFT" value="40" enum="Key" keywords="open round bracket">
+ Left parenthesis ([code]([/code]) key.
</constant>
- <constant name="KEY_PARENRIGHT" value="41" enum="Key">
- ) key.
+ <constant name="KEY_PARENRIGHT" value="41" enum="Key" keywords="close round bracket">
+ Right parenthesis ([code])[/code]) key.
</constant>
<constant name="KEY_ASTERISK" value="42" enum="Key">
- * key.
+ Asterisk ([code]*[/code]) key.
</constant>
<constant name="KEY_PLUS" value="43" enum="Key">
- + key.
+ Plus ([code]+[/code]) key.
</constant>
<constant name="KEY_COMMA" value="44" enum="Key">
- , key.
+ Comma ([code],[/code]) key.
</constant>
- <constant name="KEY_MINUS" value="45" enum="Key">
- - key.
+ <constant name="KEY_MINUS" value="45" enum="Key" keywords="hyphen">
+ Minus ([code]-[/code]) key.
</constant>
- <constant name="KEY_PERIOD" value="46" enum="Key">
- . key.
+ <constant name="KEY_PERIOD" value="46" enum="Key" keywords="dot">
+ Period ([code].[/code]) key.
</constant>
<constant name="KEY_SLASH" value="47" enum="Key">
- / key.
+ Slash ([code]/[/code]) key.
</constant>
<constant name="KEY_0" value="48" enum="Key">
Number 0 key.
@@ -2218,25 +2218,25 @@
Number 9 key.
</constant>
<constant name="KEY_COLON" value="58" enum="Key">
- : key.
+ Colon ([code]:[/code]) key.
</constant>
<constant name="KEY_SEMICOLON" value="59" enum="Key">
- ; key.
+ Semicolon ([code];[/code]) key.
</constant>
<constant name="KEY_LESS" value="60" enum="Key">
- &lt; key.
+ Less-than sign ([code]&lt;[/code]) key.
</constant>
<constant name="KEY_EQUAL" value="61" enum="Key">
- = key.
+ Equal sign ([code]=[/code]) key.
</constant>
<constant name="KEY_GREATER" value="62" enum="Key">
- &gt; key.
+ Greater-than sign ([code]&gt;[/code]) key.
</constant>
<constant name="KEY_QUESTION" value="63" enum="Key">
- ? key.
+ Question mark ([code]?[/code]) key.
</constant>
- <constant name="KEY_AT" value="64" enum="Key">
- @ key.
+ <constant name="KEY_AT" value="64" enum="Key" keywords="commercial at">
+ At sign ([code]@[/code]) key.
</constant>
<constant name="KEY_A" value="65" enum="Key">
A key.
@@ -2316,41 +2316,41 @@
<constant name="KEY_Z" value="90" enum="Key">
Z key.
</constant>
- <constant name="KEY_BRACKETLEFT" value="91" enum="Key">
- [ key.
+ <constant name="KEY_BRACKETLEFT" value="91" enum="Key" keywords="open square bracket">
+ Left bracket ([code][lb][/code]) key.
</constant>
<constant name="KEY_BACKSLASH" value="92" enum="Key">
- \ key.
+ Backslash ([code]\[/code]) key.
</constant>
- <constant name="KEY_BRACKETRIGHT" value="93" enum="Key">
- ] key.
+ <constant name="KEY_BRACKETRIGHT" value="93" enum="Key" keywords="close square bracket">
+ Right bracket ([code][rb][/code]) key.
</constant>
- <constant name="KEY_ASCIICIRCUM" value="94" enum="Key">
- ^ key.
+ <constant name="KEY_ASCIICIRCUM" value="94" enum="Key" keywords="caret">
+ Caret ([code]^[/code]) key.
</constant>
- <constant name="KEY_UNDERSCORE" value="95" enum="Key">
- _ key.
+ <constant name="KEY_UNDERSCORE" value="95" enum="Key" keywords="underline">
+ Underscore ([code]_[/code]) key.
</constant>
- <constant name="KEY_QUOTELEFT" value="96" enum="Key">
- ` key.
+ <constant name="KEY_QUOTELEFT" value="96" enum="Key" keywords="backtick, backquote">
+ Backtick ([code]`[/code]) key.
</constant>
- <constant name="KEY_BRACELEFT" value="123" enum="Key">
- { key.
+ <constant name="KEY_BRACELEFT" value="123" enum="Key" keywords="open curly bracket">
+ Left brace ([code]{[/code]) key.
</constant>
- <constant name="KEY_BAR" value="124" enum="Key">
- | key.
+ <constant name="KEY_BAR" value="124" enum="Key" keywords="pipe">
+ Vertical bar or [i]pipe[/i] ([code]|[/code]) key.
</constant>
- <constant name="KEY_BRACERIGHT" value="125" enum="Key">
- } key.
+ <constant name="KEY_BRACERIGHT" value="125" enum="Key" keywords="close curly bracket">
+ Right brace ([code]}[/code]) key.
</constant>
<constant name="KEY_ASCIITILDE" value="126" enum="Key">
- ~ key.
+ Tilde ([code]~[/code]) key.
</constant>
<constant name="KEY_YEN" value="165" enum="Key">
- ¥ key.
+ Yen symbol ([code]¥[/code]) key.
</constant>
- <constant name="KEY_SECTION" value="167" enum="Key">
- § key.
+ <constant name="KEY_SECTION" value="167" enum="Key" keywords="silcrow">
+ Section sign ([code]§[/code]) key.
</constant>
<constant name="KEY_CODE_MASK" value="8388607" enum="KeyModifierMask" is_bitfield="true">
Key Code mask.
@@ -2941,7 +2941,10 @@
[/codeblock]
[b]Note:[/b] A [Callable] cannot be properly serialized and stored in a file, so it is recommended to use [constant PROPERTY_USAGE_EDITOR] instead of [constant PROPERTY_USAGE_DEFAULT].
</constant>
- <constant name="PROPERTY_HINT_MAX" value="40" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_ONESHOT" value="40" enum="PropertyHint">
+ Hints that a property will be changed on its own after setting, such as [member AudioStreamPlayer.playing] or [member GPUParticles3D.emitting].
+ </constant>
+ <constant name="PROPERTY_HINT_MAX" value="41" enum="PropertyHint">
Represents the size of the [enum PropertyHint] enum.
</constant>
<constant name="PROPERTY_USAGE_NONE" value="0" enum="PropertyUsageFlags" is_bitfield="true">
@@ -2981,7 +2984,7 @@
Editing the property prompts the user for restarting the editor.
</constant>
<constant name="PROPERTY_USAGE_SCRIPT_VARIABLE" value="4096" enum="PropertyUsageFlags" is_bitfield="true">
- The property is a script variable which should be serialized and saved in the scene file.
+ The property is a script variable. [constant PROPERTY_USAGE_SCRIPT_VARIABLE] can be used to distinguish between exported script variables from built-in variables (which don't have this usage flag). By default, [constant PROPERTY_USAGE_SCRIPT_VARIABLE] is [b]not[/b] applied to variables that are created by overriding [method Object._get_property_list] in a script.
</constant>
<constant name="PROPERTY_USAGE_STORE_IF_NULL" value="8192" enum="PropertyUsageFlags" is_bitfield="true">
The property value of type [Object] will be stored even if its value is [code]null[/code].
@@ -2992,7 +2995,7 @@
<constant name="PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE" value="32768" enum="PropertyUsageFlags" is_bitfield="true" deprecated="This flag is not used by the engine.">
</constant>
<constant name="PROPERTY_USAGE_CLASS_IS_ENUM" value="65536" enum="PropertyUsageFlags" is_bitfield="true">
- The property is an enum, i.e. it only takes named integer constants from its associated enumeration.
+ The property is a variable of enum type, i.e. it only takes named integer constants from its associated enumeration.
</constant>
<constant name="PROPERTY_USAGE_NIL_IS_VARIANT" value="131072" enum="PropertyUsageFlags" is_bitfield="true">
If property has [code]nil[/code] as default value, its type will be [Variant].
diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml
index ae2de055cb..57ac241eb2 100644
--- a/doc/classes/AABB.xml
+++ b/doc/classes/AABB.xml
@@ -345,14 +345,14 @@
</methods>
<members>
<member name="end" type="Vector3" setter="" getter="" default="Vector3(0, 0, 0)">
- The ending point. This is usually the corner on the top-right and forward of the bounding box, and is equivalent to [code]position + size[/code]. Setting this point affects the [member size].
+ The ending point. This is usually the corner on the top-right and back of the bounding box, and is equivalent to [code]position + size[/code]. Setting this point affects the [member size].
</member>
<member name="position" type="Vector3" setter="" getter="" default="Vector3(0, 0, 0)">
- The origin point. This is usually the corner on the bottom-left and back of the bounding box.
+ The origin point. This is usually the corner on the bottom-left and forward of the bounding box.
</member>
<member name="size" type="Vector3" setter="" getter="" default="Vector3(0, 0, 0)">
The bounding box's width, height, and depth starting from [member position]. Setting this value also affects the [member end] point.
- [b]Note:[/b] It's recommended setting the width, height, and depth to non-negative values. This is because most methods in Godot assume that the [member position] is the bottom-left-back corner, and the [member end] is the top-right-forward corner. To get an equivalent bounding box with non-negative size, use [method abs].
+ [b]Note:[/b] It's recommended setting the width, height, and depth to non-negative values. This is because most methods in Godot assume that the [member position] is the bottom-left-forward corner, and the [member end] is the top-right-back corner. To get an equivalent bounding box with non-negative size, use [method abs].
</member>
</members>
<operators>
diff --git a/doc/classes/AStar2D.xml b/doc/classes/AStar2D.xml
index a41da4c318..044e1206e9 100644
--- a/doc/classes/AStar2D.xml
+++ b/doc/classes/AStar2D.xml
@@ -278,7 +278,7 @@
<return type="void" />
<param index="0" name="num_nodes" type="int" />
<description>
- Reserves space internally for [param num_nodes] points, useful if you're adding a known large number of points at once, such as points on a grid. New capacity must be greater or equals to old capacity.
+ Reserves space internally for [param num_nodes] points. Useful if you're adding a known large number of points at once, such as points on a grid. The new capacity must be greater or equal to the old capacity.
</description>
</method>
<method name="set_point_disabled">
diff --git a/doc/classes/AnimatedSprite2D.xml b/doc/classes/AnimatedSprite2D.xml
index 88e543591a..cc1e9117f9 100644
--- a/doc/classes/AnimatedSprite2D.xml
+++ b/doc/classes/AnimatedSprite2D.xml
@@ -55,7 +55,7 @@
<param index="1" name="progress" type="float" />
<description>
Sets [member frame] the [member frame_progress] to the given values. Unlike setting [member frame], this method does not reset the [member frame_progress] to [code]0.0[/code] implicitly.
- [b]Example:[/b] Change the animation while keeping the same [member frame] and [member frame_progress].
+ [b]Example:[/b] Change the animation while keeping the same [member frame] and [member frame_progress]:
[codeblocks]
[gdscript]
var current_frame = animated_sprite.get_frame()
diff --git a/doc/classes/AnimatedSprite3D.xml b/doc/classes/AnimatedSprite3D.xml
index a466fc32ac..1b1f58e5f4 100644
--- a/doc/classes/AnimatedSprite3D.xml
+++ b/doc/classes/AnimatedSprite3D.xml
@@ -54,7 +54,7 @@
<param index="1" name="progress" type="float" />
<description>
Sets [member frame] the [member frame_progress] to the given values. Unlike setting [member frame], this method does not reset the [member frame_progress] to [code]0.0[/code] implicitly.
- [b]Example:[/b] Change the animation while keeping the same [member frame] and [member frame_progress].
+ [b]Example:[/b] Change the animation while keeping the same [member frame] and [member frame_progress]:
[codeblocks]
[gdscript]
var current_frame = animated_sprite.get_frame()
diff --git a/doc/classes/AnimationLibrary.xml b/doc/classes/AnimationLibrary.xml
index 7f87ea4616..51588a6052 100644
--- a/doc/classes/AnimationLibrary.xml
+++ b/doc/classes/AnimationLibrary.xml
@@ -31,6 +31,12 @@
Returns the keys for the [Animation]s stored in the library.
</description>
</method>
+ <method name="get_animation_list_size" qualifiers="const">
+ <return type="int" />
+ <description>
+ Returns the key count for the [Animation]s stored in the library.
+ </description>
+ </method>
<method name="has_animation" qualifiers="const">
<return type="bool" />
<param index="0" name="name" type="StringName" />
diff --git a/doc/classes/AnimationMixer.xml b/doc/classes/AnimationMixer.xml
index d762ffa5a6..36cb675776 100644
--- a/doc/classes/AnimationMixer.xml
+++ b/doc/classes/AnimationMixer.xml
@@ -112,13 +112,13 @@
The most basic example is applying position to [CharacterBody3D]:
[codeblocks]
[gdscript]
- var current_rotation: Quaternion
+ var current_rotation
func _process(delta):
if Input.is_action_just_pressed("animate"):
current_rotation = get_quaternion()
state_machine.travel("Animate")
- var velocity: Vector3 = current_rotation * animation_tree.get_root_motion_position() / delta
+ var velocity = current_rotation * animation_tree.get_root_motion_position() / delta
set_velocity(velocity)
move_and_slide()
[/gdscript]
@@ -130,7 +130,20 @@
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
- var velocity: Vector3 = (animation_tree.get_root_motion_rotation_accumulator().inverse() * get_quaternion()) * animation_tree.get_root_motion_position() / delta
+ var velocity = (animation_tree.get_root_motion_rotation_accumulator().inverse() * get_quaternion()) * animation_tree.get_root_motion_position() / delta
+ set_velocity(velocity)
+ move_and_slide()
+ [/gdscript]
+ [/codeblocks]
+ If [member root_motion_local] is [code]true[/code], return the pre-multiplied translation value with the inverted rotation.
+ In this case, the code can be written as follows:
+ [codeblocks]
+ [gdscript]
+ func _process(delta):
+ if Input.is_action_just_pressed("animate"):
+ state_machine.travel("Animate")
+ set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
+ var velocity = get_quaternion() * animation_tree.get_root_motion_position() / delta
set_velocity(velocity)
move_and_slide()
[/gdscript]
@@ -145,13 +158,13 @@
For example, if an animation with only one key [code]Vector3(0, 0, 0)[/code] is played in the previous frame and then an animation with only one key [code]Vector3(1, 0, 1)[/code] is played in the next frame, the difference can be calculated as follows:
[codeblocks]
[gdscript]
- var prev_root_motion_position_accumulator: Vector3
+ var prev_root_motion_position_accumulator
func _process(delta):
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
- var current_root_motion_position_accumulator: Vector3 = animation_tree.get_root_motion_position_accumulator()
- var difference: Vector3 = current_root_motion_position_accumulator - prev_root_motion_position_accumulator
+ var current_root_motion_position_accumulator = animation_tree.get_root_motion_position_accumulator()
+ var difference = current_root_motion_position_accumulator - prev_root_motion_position_accumulator
prev_root_motion_position_accumulator = current_root_motion_position_accumulator
transform.origin += difference
[/gdscript]
@@ -185,13 +198,13 @@
For example, if an animation with only one key [code]Quaternion(0, 0, 0, 1)[/code] is played in the previous frame and then an animation with only one key [code]Quaternion(0, 0.707, 0, 0.707)[/code] is played in the next frame, the difference can be calculated as follows:
[codeblocks]
[gdscript]
- var prev_root_motion_rotation_accumulator: Quaternion
+ var prev_root_motion_rotation_accumulator
func _process(delta):
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
- var current_root_motion_rotation_accumulator: Quaternion = animation_tree.get_root_motion_rotation_accumulator()
- var difference: Quaternion = prev_root_motion_rotation_accumulator.inverse() * current_root_motion_rotation_accumulator
+ var current_root_motion_rotation_accumulator = animation_tree.get_root_motion_rotation_accumulator()
+ var difference = prev_root_motion_rotation_accumulator.inverse() * current_root_motion_rotation_accumulator
prev_root_motion_rotation_accumulator = current_root_motion_rotation_accumulator
transform.basis *= Basis(difference)
[/gdscript]
@@ -208,8 +221,8 @@
The most basic example is applying scale to [CharacterBody3D]:
[codeblocks]
[gdscript]
- var current_scale: Vector3 = Vector3(1, 1, 1)
- var scale_accum: Vector3 = Vector3(1, 1, 1)
+ var current_scale = Vector3(1, 1, 1)
+ var scale_accum = Vector3(1, 1, 1)
func _process(delta):
if Input.is_action_just_pressed("animate"):
@@ -229,13 +242,13 @@
For example, if an animation with only one key [code]Vector3(1, 1, 1)[/code] is played in the previous frame and then an animation with only one key [code]Vector3(2, 2, 2)[/code] is played in the next frame, the difference can be calculated as follows:
[codeblocks]
[gdscript]
- var prev_root_motion_scale_accumulator: Vector3
+ var prev_root_motion_scale_accumulator
func _process(delta):
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
- var current_root_motion_scale_accumulator: Vector3 = animation_tree.get_root_motion_scale_accumulator()
- var difference: Vector3 = current_root_motion_scale_accumulator - prev_root_motion_scale_accumulator
+ var current_root_motion_scale_accumulator = animation_tree.get_root_motion_scale_accumulator()
+ var difference = current_root_motion_scale_accumulator - prev_root_motion_scale_accumulator
prev_root_motion_scale_accumulator = current_root_motion_scale_accumulator
transform.basis = transform.basis.scaled(difference)
[/gdscript]
@@ -304,6 +317,9 @@
This is used by the editor. If set to [code]true[/code], the scene will be saved with the effects of the reset animation (the animation with the key [code]"RESET"[/code]) applied as if it had been seeked to time 0, with the editor keeping the values that the scene had before saving.
This makes it more convenient to preview and edit animations in the editor, as changes to the scene will not be saved as long as they are set in the reset animation.
</member>
+ <member name="root_motion_local" type="bool" setter="set_root_motion_local" getter="is_root_motion_local">
+ If [code]true[/code], [method get_root_motion_position] value is extracted as a local translation value before blending. In other words, it is treated like the translation is done after the rotation.
+ </member>
<member name="root_motion_track" type="NodePath" setter="set_root_motion_track" getter="get_root_motion_track" default="NodePath(&quot;&quot;)">
The path to the Animation track used for root motion. Paths must be valid scene-tree paths to a node, and must be specified starting from the parent node of the node that will reproduce the animation. The [member root_motion_track] uses the same format as [method Animation.track_set_path], but note that a bone must be specified.
If the track has type [constant Animation.TYPE_POSITION_3D], [constant Animation.TYPE_ROTATION_3D], or [constant Animation.TYPE_SCALE_3D] the transformation will be canceled visually, and the animation will appear to stay in place. See also [method get_root_motion_position], [method get_root_motion_rotation], [method get_root_motion_scale], and [RootMotionView].
diff --git a/doc/classes/AnimationNodeAnimation.xml b/doc/classes/AnimationNodeAnimation.xml
index 70c3e5a26e..f4490bc167 100644
--- a/doc/classes/AnimationNodeAnimation.xml
+++ b/doc/classes/AnimationNodeAnimation.xml
@@ -12,6 +12,10 @@
<link title="Third Person Shooter (TPS) Demo">https://godotengine.org/asset-library/asset/2710</link>
</tutorials>
<members>
+ <member name="advance_on_start" type="bool" setter="set_advance_on_start" getter="is_advance_on_start" default="false">
+ If [code]true[/code], on receiving a request to play an animation from the start, the first frame is not drawn, but only processed, and playback starts from the next frame.
+ See also the notes of [method AnimationPlayer.play].
+ </member>
<member name="animation" type="StringName" setter="set_animation" getter="get_animation" default="&amp;&quot;&quot;">
Animation to use as an output. It is one of the animations provided by [member AnimationTree.anim_player].
</member>
diff --git a/doc/classes/AnimationNodeTimeSeek.xml b/doc/classes/AnimationNodeTimeSeek.xml
index d00b3fca3a..865e94ec43 100644
--- a/doc/classes/AnimationNodeTimeSeek.xml
+++ b/doc/classes/AnimationNodeTimeSeek.xml
@@ -30,4 +30,9 @@
<tutorials>
<link title="Using AnimationTree">$DOCS_URL/tutorials/animation/animation_tree.html</link>
</tutorials>
+ <members>
+ <member name="explicit_elapse" type="bool" setter="set_explicit_elapse" getter="is_explicit_elapse" default="true">
+ If [code]true[/code], some processes are executed to handle keys between seeks, such as calculating root motion and finding the nearest discrete key.
+ </member>
+ </members>
</class>
diff --git a/doc/classes/Area2D.xml b/doc/classes/Area2D.xml
index 4ad5db2b67..61a103f20d 100644
--- a/doc/classes/Area2D.xml
+++ b/doc/classes/Area2D.xml
@@ -132,7 +132,7 @@
<description>
Emitted when a [Shape2D] of the received [param area] enters a shape of this area. Requires [member monitoring] to be set to [code]true[/code].
[param local_shape_index] and [param area_shape_index] contain indices of the interacting shapes from this area and the other area, respectively. [param area_rid] contains the [RID] of the other area. These values can be used with the [PhysicsServer2D].
- [b]Example of getting the[/b] [CollisionShape2D] [b]node from the shape index:[/b]
+ [b]Example:[/b] Get the [CollisionShape2D] node from the shape index:
[codeblocks]
[gdscript]
var other_shape_owner = area.shape_find_owner(area_shape_index)
@@ -174,7 +174,7 @@
<description>
Emitted when a [Shape2D] of the received [param body] enters a shape of this area. [param body] can be a [PhysicsBody2D] or a [TileMap]. [TileMap]s are detected if their [TileSet] has collision shapes configured. Requires [member monitoring] to be set to [code]true[/code].
[param local_shape_index] and [param body_shape_index] contain indices of the interacting shapes from this area and the interacting body, respectively. [param body_rid] contains the [RID] of the body. These values can be used with the [PhysicsServer2D].
- [b]Example of getting the[/b] [CollisionShape2D] [b]node from the shape index:[/b]
+ [b]Example:[/b] Get the [CollisionShape2D] node from the shape index:
[codeblocks]
[gdscript]
var body_shape_owner = body.shape_find_owner(body_shape_index)
diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml
index 8eedd3cdf2..aac98593ff 100644
--- a/doc/classes/Area3D.xml
+++ b/doc/classes/Area3D.xml
@@ -156,7 +156,7 @@
<description>
Emitted when a [Shape3D] of the received [param area] enters a shape of this area. Requires [member monitoring] to be set to [code]true[/code].
[param local_shape_index] and [param area_shape_index] contain indices of the interacting shapes from this area and the other area, respectively. [param area_rid] contains the [RID] of the other area. These values can be used with the [PhysicsServer3D].
- [b]Example of getting the[/b] [CollisionShape3D] [b]node from the shape index:[/b]
+ [b]Example:[/b] Get the [CollisionShape3D] node from the shape index:
[codeblocks]
[gdscript]
var other_shape_owner = area.shape_find_owner(area_shape_index)
@@ -198,7 +198,7 @@
<description>
Emitted when a [Shape3D] of the received [param body] enters a shape of this area. [param body] can be a [PhysicsBody3D] or a [GridMap]. [GridMap]s are detected if their [MeshLibrary] has collision shapes configured. Requires [member monitoring] to be set to [code]true[/code].
[param local_shape_index] and [param body_shape_index] contain indices of the interacting shapes from this area and the interacting body, respectively. [param body_rid] contains the [RID] of the body. These values can be used with the [PhysicsServer3D].
- [b]Example of getting the[/b] [CollisionShape3D] [b]node from the shape index:[/b]
+ [b]Example:[/b] Get the [CollisionShape3D] node from the shape index:
[codeblocks]
[gdscript]
var body_shape_owner = body.shape_find_owner(body_shape_index)
diff --git a/doc/classes/AudioEffectSpectrumAnalyzer.xml b/doc/classes/AudioEffectSpectrumAnalyzer.xml
index b90f87ef5b..5cbf3fb1cb 100644
--- a/doc/classes/AudioEffectSpectrumAnalyzer.xml
+++ b/doc/classes/AudioEffectSpectrumAnalyzer.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
This audio effect does not affect sound output, but can be used for real-time audio visualizations.
- This resource configures an [AudioEffectSpectrumAnalyzerInstance], which performs the actual analysis at runtime. An instance can be acquired with [method AudioServer.get_bus_effect_instance].
+ This resource configures an [AudioEffectSpectrumAnalyzerInstance], which performs the actual analysis at runtime. An instance can be obtained with [method AudioServer.get_bus_effect_instance].
See also [AudioStreamGenerator] for procedurally generating sounds.
</description>
<tutorials>
diff --git a/doc/classes/AudioEffectSpectrumAnalyzerInstance.xml b/doc/classes/AudioEffectSpectrumAnalyzerInstance.xml
index 184f80db2e..833ccafa6f 100644
--- a/doc/classes/AudioEffectSpectrumAnalyzerInstance.xml
+++ b/doc/classes/AudioEffectSpectrumAnalyzerInstance.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
The runtime part of an [AudioEffectSpectrumAnalyzer], which can be used to query the magnitude of a frequency range on its host bus.
- An instance of this class can be acquired with [method AudioServer.get_bus_effect_instance].
+ An instance of this class can be obtained with [method AudioServer.get_bus_effect_instance].
</description>
<tutorials>
<link title="Audio Spectrum Visualizer Demo">https://godotengine.org/asset-library/asset/2762</link>
diff --git a/doc/classes/AudioStream.xml b/doc/classes/AudioStream.xml
index 44edff122e..d11e070d89 100644
--- a/doc/classes/AudioStream.xml
+++ b/doc/classes/AudioStream.xml
@@ -48,7 +48,7 @@
<method name="_instantiate_playback" qualifiers="virtual const">
<return type="AudioStreamPlayback" />
<description>
- Override this method to customize the returned value of [method instantiate_playback]. Should returned a new [AudioStreamPlayback] created when the stream is played (such as by an [AudioStreamPlayer])..
+ Override this method to customize the returned value of [method instantiate_playback]. Should return a new [AudioStreamPlayback] created when the stream is played (such as by an [AudioStreamPlayer]).
</description>
</method>
<method name="_is_monophonic" qualifiers="virtual const">
diff --git a/doc/classes/AudioStreamPlayer.xml b/doc/classes/AudioStreamPlayer.xml
index 93680de21e..900318e4f4 100644
--- a/doc/classes/AudioStreamPlayer.xml
+++ b/doc/classes/AudioStreamPlayer.xml
@@ -22,6 +22,7 @@
<description>
Returns the position in the [AudioStream] of the latest sound, in seconds. Returns [code]0.0[/code] if no sounds are playing.
[b]Note:[/b] The position is not always accurate, as the [AudioServer] does not mix audio every processed frame. To get more accurate results, add [method AudioServer.get_time_since_last_mix] to the returned position.
+ [b]Note:[/b] This method always returns [code]0.0[/code] if the [member stream] is an [AudioStreamInteractive], since it can have multiple clips playing at once.
</description>
</method>
<method name="get_stream_playback">
diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml
index 92faa55fe0..59c1195b00 100644
--- a/doc/classes/Basis.xml
+++ b/doc/classes/Basis.xml
@@ -304,7 +304,7 @@
<param index="1" name="weight" type="float" />
<description>
Performs a spherical-linear interpolation with the [param to] basis, given a [param weight]. Both this basis and [param to] should represent a rotation.
- [b]Example:[/b] Smoothly rotate a [Node3D] to the target basis over time, with a [Tween].
+ [b]Example:[/b] Smoothly rotate a [Node3D] to the target basis over time, with a [Tween]:
[codeblock]
var start_basis = Basis.IDENTITY
var target_basis = Basis.IDENTITY.rotated(Vector3.UP, TAU / 2)
diff --git a/doc/classes/Button.xml b/doc/classes/Button.xml
index c774667a7d..5b3f86c9f5 100644
--- a/doc/classes/Button.xml
+++ b/doc/classes/Button.xml
@@ -5,13 +5,13 @@
</brief_description>
<description>
[Button] is the standard themed button. It can contain text and an icon, and it will display them according to the current [Theme].
- [b]Example of creating a button and assigning an action when pressed by code:[/b]
+ [b]Example:[/b] Create a button and connect a method that will be called when the button is pressed:
[codeblocks]
[gdscript]
func _ready():
var button = Button.new()
button.text = "Click me"
- button.pressed.connect(self._button_pressed)
+ button.pressed.connect(_button_pressed)
add_child(button)
func _button_pressed():
@@ -33,7 +33,7 @@
[/csharp]
[/codeblocks]
See also [BaseButton] which contains common properties and methods associated with this node.
- [b]Note:[/b] Buttons do not interpret touch input and therefore don't support multitouch, since mouse emulation can only press one button at a given time. Use [TouchScreenButton] for buttons that trigger gameplay movement or actions.
+ [b]Note:[/b] Buttons do not detect touch input and therefore don't support multitouch, since mouse emulation can only press one button at a given time. Use [TouchScreenButton] for buttons that trigger gameplay movement or actions.
</description>
<tutorials>
<link title="2D Dodge The Creeps Demo">https://godotengine.org/asset-library/asset/2712</link>
diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml
index 99411c73aa..e8fa13fd0d 100644
--- a/doc/classes/CPUParticles2D.xml
+++ b/doc/classes/CPUParticles2D.xml
@@ -43,7 +43,7 @@
<return type="bool" />
<param index="0" name="particle_flag" type="int" enum="CPUParticles2D.ParticleFlags" />
<description>
- Returns the enabled state of the given flag (see [enum ParticleFlags] for options).
+ Returns the enabled state of the given particle flag (see [enum ParticleFlags] for options).
</description>
</method>
<method name="restart">
diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml
index 0c8f3c66f5..cf3c3e06fd 100644
--- a/doc/classes/Callable.xml
+++ b/doc/classes/Callable.xml
@@ -155,13 +155,21 @@
<method name="get_bound_arguments" qualifiers="const">
<return type="Array" />
<description>
- Return the bound arguments (as long as [method get_bound_arguments_count] is greater than zero), or empty (if [method get_bound_arguments_count] is less than or equal to zero).
+ Returns the array of arguments bound via successive [method bind] or [method unbind] calls. These arguments will be added [i]after[/i] the arguments passed to the call, from which [method get_unbound_arguments_count] arguments on the right have been previously excluded.
+ [codeblock]
+ func get_effective_arguments(callable, call_args):
+ assert(call_args.size() - callable.get_unbound_arguments_count() &gt;= 0)
+ var result = call_args.slice(0, call_args.size() - callable.get_unbound_arguments_count())
+ result.append_array(callable.get_bound_arguments())
+ return result
+ [/codeblock]
</description>
</method>
<method name="get_bound_arguments_count" qualifiers="const">
<return type="int" />
<description>
- Returns the total amount of arguments bound (or unbound) via successive [method bind] or [method unbind] calls. If the amount of arguments unbound is greater than the ones bound, this function returns a value less than zero.
+ Returns the total amount of arguments bound via successive [method bind] or [method unbind] calls. This is the same as the size of the array returned by [method get_bound_arguments]. See [method get_bound_arguments] for details.
+ [b]Note:[/b] The [method get_bound_arguments_count] and [method get_unbound_arguments_count] methods can both return positive values.
</description>
</method>
<method name="get_method" qualifiers="const">
@@ -182,6 +190,13 @@
Returns the ID of this [Callable]'s object (see [method Object.get_instance_id]).
</description>
</method>
+ <method name="get_unbound_arguments_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Returns the total amount of arguments unbound via successive [method bind] or [method unbind] calls. See [method get_bound_arguments] for details.
+ [b]Note:[/b] The [method get_bound_arguments_count] and [method get_unbound_arguments_count] methods can both return positive values.
+ </description>
+ </method>
<method name="hash" qualifiers="const">
<return type="int" />
<description>
diff --git a/doc/classes/CallbackTweener.xml b/doc/classes/CallbackTweener.xml
index afb9e70601..3a617d2a43 100644
--- a/doc/classes/CallbackTweener.xml
+++ b/doc/classes/CallbackTweener.xml
@@ -16,7 +16,7 @@
<param index="0" name="delay" type="float" />
<description>
Makes the callback call delayed by given time in seconds.
- [b]Example:[/b] Call [method Node.queue_free] after 2 seconds.
+ [b]Example:[/b] Call [method Node.queue_free] after 2 seconds:
[codeblock]
var tween = get_tree().create_tween()
tween.tween_callback(queue_free).set_delay(2)
diff --git a/doc/classes/CameraAttributes.xml b/doc/classes/CameraAttributes.xml
index 1b1365eed4..cb5a7778de 100644
--- a/doc/classes/CameraAttributes.xml
+++ b/doc/classes/CameraAttributes.xml
@@ -25,7 +25,9 @@
Multiplier for the exposure amount. A higher value results in a brighter image.
</member>
<member name="exposure_sensitivity" type="float" setter="set_exposure_sensitivity" getter="get_exposure_sensitivity" default="100.0">
- Sensitivity of camera sensors, measured in ISO. A higher sensitivity results in a brighter image. Only available when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is enabled. When [member auto_exposure_enabled] this can be used as a method of exposure compensation, doubling the value will increase the exposure value (measured in EV100) by 1 stop.
+ Sensitivity of camera sensors, measured in ISO. A higher sensitivity results in a brighter image.
+ If [member auto_exposure_enabled] is [code]true[/code], this can be used as a method of exposure compensation, doubling the value will increase the exposure value (measured in EV100) by 1 stop.
+ [b]Note:[/b] Only available when [member ProjectSettings.rendering/lights_and_shadows/use_physical_light_units] is enabled.
</member>
</members>
</class>
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index 78e9c392db..5710e08423 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -333,7 +333,7 @@
<param index="9" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
Draws [param text] using the specified [param font] at the [param pos] (bottom-left corner using the baseline of the font). The text will have its color multiplied by [param modulate]. If [param width] is greater than or equal to 0, the text will be clipped if it exceeds the specified width.
- [b]Example using the default project font:[/b]
+ [b]Example:[/b] Draw "Hello world", using the project's default font:
[codeblocks]
[gdscript]
# If using this method in a script that redraws constantly, move the
@@ -594,6 +594,7 @@
<members>
<member name="clip_children" type="int" setter="set_clip_children_mode" getter="get_clip_children_mode" enum="CanvasItem.ClipChildrenMode" default="0">
Allows the current node to clip child nodes, essentially acting as a mask.
+ [b]Note:[/b] Clipping nodes cannot be nested or placed within [CanvasGroup]s. If an ancestor of this node clips its children or is a [CanvasGroup], then this node's clip mode should be set to [constant CLIP_CHILDREN_DISABLED] to avoid unexpected behavior.
</member>
<member name="light_mask" type="int" setter="set_light_mask" getter="get_light_mask" default="1">
The rendering layers in which this [CanvasItem] responds to [Light2D] nodes.
@@ -632,7 +633,7 @@
</member>
<member name="y_sort_enabled" type="bool" setter="set_y_sort_enabled" getter="is_y_sort_enabled" default="false">
If [code]true[/code], this and child [CanvasItem] nodes with a higher Y position are rendered in front of nodes with a lower Y position. If [code]false[/code], this and child [CanvasItem] nodes are rendered normally in scene tree order.
- With Y-sorting enabled on a parent node ('A') but disabled on a child node ('B'), the child node ('B') is sorted but its children ('C1', 'C2', etc) render together on the same Y position as the child node ('B'). This allows you to organize the render order of a scene without changing the scene tree.
+ With Y-sorting enabled on a parent node ('A') but disabled on a child node ('B'), the child node ('B') is sorted but its children ('C1', 'C2', etc.) render together on the same Y position as the child node ('B'). This allows you to organize the render order of a scene without changing the scene tree.
Nodes sort relative to each other only if they are on the same [member z_index].
</member>
<member name="z_as_relative" type="bool" setter="set_z_as_relative" getter="is_z_relative" default="true">
diff --git a/doc/classes/CharacterBody2D.xml b/doc/classes/CharacterBody2D.xml
index ede4d63cfc..30438be18b 100644
--- a/doc/classes/CharacterBody2D.xml
+++ b/doc/classes/CharacterBody2D.xml
@@ -69,7 +69,7 @@
<param index="0" name="slide_idx" type="int" />
<description>
Returns a [KinematicCollision2D], which contains information about a collision that occurred during the last call to [method move_and_slide]. Since the body can collide several times in a single call to [method move_and_slide], you must specify the index of the collision in the range 0 to ([method get_slide_collision_count] - 1).
- [b]Example usage:[/b]
+ [b]Example:[/b] Iterate through the collisions with a [code]for[/code] loop:
[codeblocks]
[gdscript]
for i in get_slide_collision_count():
diff --git a/doc/classes/CodeEdit.xml b/doc/classes/CodeEdit.xml
index 136b8e5fc5..a65d587e8b 100644
--- a/doc/classes/CodeEdit.xml
+++ b/doc/classes/CodeEdit.xml
@@ -80,7 +80,7 @@
<return type="bool" />
<param index="0" name="line" type="int" />
<description>
- Returns if the given line is foldable, that is, it has indented lines right below it or a comment / string block.
+ Returns [code]true[/code] if the given line is foldable. A line is foldable if it is the start of a valid code region (see [method get_code_region_start_tag]), if it is the start of a comment or string block, or if the next non-empty line is more indented (see [method TextEdit.get_indent_level]).
</description>
</method>
<method name="cancel_code_completion">
@@ -153,7 +153,7 @@
<method name="do_indent">
<return type="void" />
<description>
- Perform an indent as if the user activated the "ui_text_indent" action.
+ If there is no selection, indentation is inserted at the caret. Otherwise, the selected lines are indented like [method indent_lines]. Equivalent to the [member ProjectSettings.input/ui_text_indent] action. The indentation characters used depend on [member indent_use_spaces] and [member indent_size].
</description>
</method>
<method name="duplicate_lines">
@@ -276,7 +276,7 @@
<method name="get_folded_lines" qualifiers="const">
<return type="int[]" />
<description>
- Returns all lines that are current folded.
+ Returns all lines that are currently folded.
</description>
</method>
<method name="get_text_for_code_completion" qualifiers="const">
@@ -330,7 +330,7 @@
<method name="indent_lines">
<return type="void" />
<description>
- Indents selected lines, or in the case of no selection the caret line by one.
+ Indents all lines that are selected or have a caret on them. Uses spaces or a tab depending on [member indent_use_spaces]. See [method unindent_lines].
</description>
</method>
<method name="is_in_comment" qualifiers="const">
@@ -353,42 +353,42 @@
<return type="bool" />
<param index="0" name="line" type="int" />
<description>
- Returns whether the line at the specified index is bookmarked or not.
+ Returns [code]true[/code] if the given line is bookmarked. See [method set_line_as_bookmarked].
</description>
</method>
<method name="is_line_breakpointed" qualifiers="const">
<return type="bool" />
<param index="0" name="line" type="int" />
<description>
- Returns whether the line at the specified index is breakpointed or not.
+ Returns [code]true[/code] if the given line is breakpointed. See [method set_line_as_breakpoint].
</description>
</method>
<method name="is_line_code_region_end" qualifiers="const">
<return type="bool" />
<param index="0" name="line" type="int" />
<description>
- Returns whether the line at the specified index is a code region end.
+ Returns [code]true[/code] if the given line is a code region end. See [method set_code_region_tags].
</description>
</method>
<method name="is_line_code_region_start" qualifiers="const">
<return type="bool" />
<param index="0" name="line" type="int" />
<description>
- Returns whether the line at the specified index is a code region start.
+ Returns [code]true[/code] if the given line is a code region start. See [method set_code_region_tags].
</description>
</method>
<method name="is_line_executing" qualifiers="const">
<return type="bool" />
<param index="0" name="line" type="int" />
<description>
- Returns whether the line at the specified index is marked as executing or not.
+ Returns [code]true[/code] if the given line is marked as executing. See [method set_line_as_executing].
</description>
</method>
<method name="is_line_folded" qualifiers="const">
<return type="bool" />
<param index="0" name="line" type="int" />
<description>
- Returns whether the line at the specified index is folded or not.
+ Returns [code]true[/code] if the given line is folded. See [method fold_line].
</description>
</method>
<method name="move_lines_down">
@@ -442,7 +442,7 @@
<return type="void" />
<param index="0" name="draw_below" type="bool" />
<description>
- Sets if the code hint should draw below the text.
+ If [code]true[/code], the code hint will draw below the main caret. If [code]false[/code], the code hint will draw above the main caret. See [method set_code_hint].
</description>
</method>
<method name="set_code_region_tags">
@@ -458,7 +458,7 @@
<param index="0" name="line" type="int" />
<param index="1" name="bookmarked" type="bool" />
<description>
- Sets the line as bookmarked.
+ Sets the given line as bookmarked. If [code]true[/code] and [member gutters_draw_bookmarks] is [code]true[/code], draws the [theme_item bookmark] icon in the gutter for this line. See [method get_bookmarked_lines] and [method is_line_bookmarked].
</description>
</method>
<method name="set_line_as_breakpoint">
@@ -466,7 +466,7 @@
<param index="0" name="line" type="int" />
<param index="1" name="breakpointed" type="bool" />
<description>
- Sets the line as breakpointed.
+ Sets the given line as a breakpoint. If [code]true[/code] and [member gutters_draw_breakpoints_gutter] is [code]true[/code], draws the [theme_item breakpoint] icon in the gutter for this line. See [method get_breakpointed_lines] and [method is_line_breakpointed].
</description>
</method>
<method name="set_line_as_executing">
@@ -474,7 +474,7 @@
<param index="0" name="line" type="int" />
<param index="1" name="executing" type="bool" />
<description>
- Sets the line as executing.
+ Sets the given line as executing. If [code]true[/code] and [member gutters_draw_executing_lines] is [code]true[/code], draws the [theme_item executing_line] icon in the gutter for this line. See [method get_executing_lines] and [method is_line_executing].
</description>
</method>
<method name="set_symbol_lookup_word_as_valid">
@@ -500,20 +500,20 @@
<method name="unfold_all_lines">
<return type="void" />
<description>
- Unfolds all lines, folded or not.
+ Unfolds all lines that are folded.
</description>
</method>
<method name="unfold_line">
<return type="void" />
<param index="0" name="line" type="int" />
<description>
- Unfolds all lines that were previously folded.
+ Unfolds the given line if it is folded or if it is hidden under a folded line.
</description>
</method>
<method name="unindent_lines">
<return type="void" />
<description>
- Unindents selected lines, or in the case of no selection the caret line by one. Same as performing "ui_text_unindent" action.
+ Unindents all lines that are selected or have a caret on them. Uses spaces or a tab depending on [member indent_use_spaces]. Equivalent to the [member ProjectSettings.input/ui_text_dedent] action. See [method indent_lines].
</description>
</method>
<method name="update_code_completion_options">
@@ -527,16 +527,16 @@
</methods>
<members>
<member name="auto_brace_completion_enabled" type="bool" setter="set_auto_brace_completion_enabled" getter="is_auto_brace_completion_enabled" default="false">
- Sets whether brace pairs should be autocompleted.
+ If [code]true[/code], uses [member auto_brace_completion_pairs] to automatically insert the closing brace when the opening brace is inserted by typing or autocompletion. Also automatically removes the closing brace when using backspace on the opening brace.
</member>
<member name="auto_brace_completion_highlight_matching" type="bool" setter="set_highlight_matching_braces_enabled" getter="is_highlight_matching_braces_enabled" default="false">
- Highlight mismatching brace pairs.
+ If [code]true[/code], highlights brace pairs when the caret is on either one, using [member auto_brace_completion_pairs]. If matching, the pairs will be underlined. If a brace is unmatched, it is colored with [theme_item brace_mismatch_color].
</member>
<member name="auto_brace_completion_pairs" type="Dictionary" setter="set_auto_brace_completion_pairs" getter="get_auto_brace_completion_pairs" default="{ &quot;\&quot;&quot;: &quot;\&quot;&quot;, &quot;&apos;&quot;: &quot;&apos;&quot;, &quot;(&quot;: &quot;)&quot;, &quot;[&quot;: &quot;]&quot;, &quot;{&quot;: &quot;}&quot; }">
- Sets the brace pairs to be autocompleted.
+ Sets the brace pairs to be autocompleted. For each entry in the dictionary, the key is the opening brace and the value is the closing brace that matches it. A brace is a [String] made of symbols. See [member auto_brace_completion_enabled] and [member auto_brace_completion_highlight_matching].
</member>
<member name="code_completion_enabled" type="bool" setter="set_code_completion_enabled" getter="is_code_completion_enabled" default="false">
- Sets whether code completion is allowed.
+ If [code]true[/code], the [member ProjectSettings.input/ui_text_completion_query] action requests code completion. To handle it, see [method _request_code_completion] or [signal code_completion_requested].
</member>
<member name="code_completion_prefixes" type="String[]" setter="set_code_completion_prefixes" getter="get_code_completion_prefixes" default="[]">
Sets prefixes that will trigger code completion.
@@ -548,28 +548,28 @@
Sets the string delimiters. All existing string delimiters will be removed.
</member>
<member name="gutters_draw_bookmarks" type="bool" setter="set_draw_bookmarks_gutter" getter="is_drawing_bookmarks_gutter" default="false">
- Sets if bookmarked should be drawn in the gutter. This gutter is shared with breakpoints and executing lines.
+ If [code]true[/code], bookmarks are drawn in the gutter. This gutter is shared with breakpoints and executing lines. See [method set_line_as_bookmarked].
</member>
<member name="gutters_draw_breakpoints_gutter" type="bool" setter="set_draw_breakpoints_gutter" getter="is_drawing_breakpoints_gutter" default="false">
- Sets if breakpoints should be drawn in the gutter. This gutter is shared with bookmarks and executing lines.
+ If [code]true[/code], breakpoints are drawn in the gutter. This gutter is shared with bookmarks and executing lines. Clicking the gutter will toggle the breakpoint for the line, see [method set_line_as_breakpoint].
</member>
<member name="gutters_draw_executing_lines" type="bool" setter="set_draw_executing_lines_gutter" getter="is_drawing_executing_lines_gutter" default="false">
- Sets if executing lines should be marked in the gutter. This gutter is shared with breakpoints and bookmarks lines.
+ If [code]true[/code], executing lines are marked in the gutter. This gutter is shared with breakpoints and bookmarks. See [method set_line_as_executing].
</member>
<member name="gutters_draw_fold_gutter" type="bool" setter="set_draw_fold_gutter" getter="is_drawing_fold_gutter" default="false">
- Sets if foldable lines icons should be drawn in the gutter.
+ If [code]true[/code], the fold gutter is drawn. In this gutter, the [theme_item can_fold_code_region] icon is drawn for each foldable line (see [method can_fold_line]) and the [theme_item folded_code_region] icon is drawn for each folded line (see [method is_line_folded]). These icons can be clicked to toggle the fold state, see [method toggle_foldable_line]. [member line_folding] must be [code]true[/code] to show icons.
</member>
<member name="gutters_draw_line_numbers" type="bool" setter="set_draw_line_numbers" getter="is_draw_line_numbers_enabled" default="false">
- Sets if line numbers should be drawn in the gutter.
+ If [code]true[/code], the line number gutter is drawn. Line numbers start at [code]1[/code] and are incremented for each line of text. Clicking and dragging in the line number gutter will select entire lines of text.
</member>
<member name="gutters_zero_pad_line_numbers" type="bool" setter="set_line_numbers_zero_padded" getter="is_line_numbers_zero_padded" default="false">
- Sets if line numbers drawn in the gutter are zero padded.
+ If [code]true[/code], line numbers drawn in the gutter are zero padded based on the total line count. Requires [member gutters_draw_line_numbers] to be set to [code]true[/code].
</member>
<member name="indent_automatic" type="bool" setter="set_auto_indent_enabled" getter="is_auto_indent_enabled" default="false">
- Sets whether automatic indent are enabled, this will add an extra indent if a prefix or brace is found.
+ If [code]true[/code], an extra indent is automatically inserted when a new line is added and a prefix in [member indent_automatic_prefixes] is found. If a brace pair opening key is found, the matching closing brace will be moved to another new line (see [member auto_brace_completion_pairs]).
</member>
<member name="indent_automatic_prefixes" type="String[]" setter="set_auto_indent_prefixes" getter="get_auto_indent_prefixes" default="[&quot;:&quot;, &quot;{&quot;, &quot;[&quot;, &quot;(&quot;]">
- Prefixes to trigger an automatic indent.
+ Prefixes to trigger an automatic indent. Used when [member indent_automatic] is set to [code]true[/code].
</member>
<member name="indent_size" type="int" setter="set_indent_size" getter="get_indent_size" default="4">
Size of the tabulation indent (one [kbd]Tab[/kbd] press) in characters. If [member indent_use_spaces] is enabled the number of spaces to use.
@@ -579,7 +579,7 @@
</member>
<member name="layout_direction" type="int" setter="set_layout_direction" getter="get_layout_direction" overrides="Control" enum="Control.LayoutDirection" default="2" />
<member name="line_folding" type="bool" setter="set_line_folding_enabled" getter="is_line_folding_enabled" default="false">
- Sets whether line folding is allowed.
+ If [code]true[/code], lines can be folded. Otherwise, line folding methods like [method fold_line] will not work and [method can_fold_line] will always return [code]false[/code]. See [member gutters_draw_fold_gutter].
</member>
<member name="line_length_guidelines" type="int[]" setter="set_line_length_guidelines" getter="get_line_length_guidelines" default="[]">
Draws vertical lines at the provided columns. The first entry is considered a main hard guideline and is draw more prominently.
@@ -598,7 +598,7 @@
</signal>
<signal name="code_completion_requested">
<description>
- Emitted when the user requests code completion.
+ Emitted when the user requests code completion. This signal will not be sent if [method _request_code_completion] is overridden or [member code_completion_enabled] is [code]false[/code].
</description>
</signal>
<signal name="symbol_lookup">
diff --git a/doc/classes/CollisionShape3D.xml b/doc/classes/CollisionShape3D.xml
index a4e0ed0b28..69a7dd2b36 100644
--- a/doc/classes/CollisionShape3D.xml
+++ b/doc/classes/CollisionShape3D.xml
@@ -29,6 +29,12 @@
</method>
</methods>
<members>
+ <member name="debug_color" type="Color" setter="set_debug_color" getter="get_debug_color" default="Color(0, 0, 0, 0)">
+ The collision shape color that is displayed in the editor, or in the running project if [b]Debug &gt; Visible Collision Shapes[/b] is checked at the top of the editor. If this is reset to its default value of [code]Color(0, 0, 0, 0)[/code], the value of [member ProjectSettings.debug/shapes/collision/shape_color] will be used instead.
+ </member>
+ <member name="debug_fill" type="bool" setter="set_enable_debug_fill" getter="get_enable_debug_fill" default="true">
+ If [code]true[/code], when the shape is displayed, it will show a solid fill color in addition to its wireframe.
+ </member>
<member name="disabled" type="bool" setter="set_disabled" getter="is_disabled" default="false" keywords="enabled">
A disabled collision shape has no effect in the world.
</member>
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index 0131f8f4af..d22be4a52d 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -12,7 +12,7 @@
Call [method accept_event] so no other node receives the event. Once you accept an input, it becomes handled so [method Node._unhandled_input] will not process it.
Only one [Control] node can be in focus. Only the node in focus will receive events. To get the focus, call [method grab_focus]. [Control] nodes lose focus when another node grabs it, or if you hide the node in focus.
Sets [member mouse_filter] to [constant MOUSE_FILTER_IGNORE] to tell a [Control] node to ignore mouse or touch events. You'll need it if you place an icon on top of a button.
- [Theme] resources change the Control's appearance. If you change the [Theme] on a [Control] node, it affects all of its children. To override some of the theme's parameters, call one of the [code]add_theme_*_override[/code] methods, like [method add_theme_font_override]. You can override the theme with the Inspector.
+ [Theme] resources change the control's appearance. The [member theme] of a [Control] node affects all of its direct and indirect children (as long as a chain of controls is uninterrupted). To override some of the theme items, call one of the [code]add_theme_*_override[/code] methods, like [method add_theme_font_override]. You can also override theme items in the Inspector.
[b]Note:[/b] Theme items are [i]not[/i] [Object] properties. This means you can't access their values using [method Object.get] and [method Object.set]. Instead, use the [code]get_theme_*[/code] and [code]add_theme_*_override[/code] methods provided by this class.
</description>
<tutorials>
@@ -120,8 +120,8 @@
<return type="void" />
<param index="0" name="event" type="InputEvent" />
<description>
- Virtual method to be implemented by the user. Use this method to process and accept inputs on UI elements. See [method accept_event].
- [b]Example usage for clicking a control:[/b]
+ Virtual method to be implemented by the user. Override this method to handle and accept inputs on UI elements. See also [method accept_event].
+ [b]Example:[/b] Click on the control to print a message:
[codeblocks]
[gdscript]
func _gui_input(event):
@@ -142,13 +142,13 @@
}
[/csharp]
[/codeblocks]
- The event won't trigger if:
- * clicking outside the control (see [method _has_point]);
- * control has [member mouse_filter] set to [constant MOUSE_FILTER_IGNORE];
- * control is obstructed by another [Control] on top of it, which doesn't have [member mouse_filter] set to [constant MOUSE_FILTER_IGNORE];
- * control's parent has [member mouse_filter] set to [constant MOUSE_FILTER_STOP] or has accepted the event;
- * it happens outside the parent's rectangle and the parent has either [member clip_contents] enabled.
- [b]Note:[/b] Event position is relative to the control origin.
+ If the [param event] inherits [InputEventMouse], this method will [b]not[/b] be called when:
+ - the control's [member mouse_filter] is set to [constant MOUSE_FILTER_IGNORE];
+ - the control is obstructed by another control on top, that doesn't have [member mouse_filter] set to [constant MOUSE_FILTER_IGNORE];
+ - the control's parent has [member mouse_filter] set to [constant MOUSE_FILTER_STOP] or has accepted the event;
+ - the control's parent has [member clip_contents] enabled and the [param event]'s position is outside the parent's rectangle;
+ - the [param event]'s position is outside the control (see [method _has_point]).
+ [b]Note:[/b] The [param event]'s position is relative to this control's origin.
</description>
</method>
<method name="_has_point" qualifiers="virtual const">
@@ -168,8 +168,8 @@
The returned node must be of type [Control] or Control-derived. It can have child nodes of any type. It is freed when the tooltip disappears, so make sure you always provide a new instance (if you want to use a pre-existing node from your scene tree, you can duplicate it and pass the duplicated instance). When [code]null[/code] or a non-Control node is returned, the default tooltip will be used instead.
The returned node will be added as child to a [PopupPanel], so you should only provide the contents of that panel. That [PopupPanel] can be themed using [method Theme.set_stylebox] for the type [code]"TooltipPanel"[/code] (see [member tooltip_text] for an example).
[b]Note:[/b] The tooltip is shrunk to minimal size. If you want to ensure it's fully visible, you might want to set its [member custom_minimum_size] to some non-zero value.
- [b]Note:[/b] The node (and any relevant children) should be [member CanvasItem.visible] when returned, otherwise, the viewport that instantiates it will not be able to calculate its minimum size reliably.
- [b]Example of usage with a custom-constructed node:[/b]
+ [b]Note:[/b] The node (and any relevant children) should have their [member CanvasItem.visible] set to [code]true[/code] when returned, otherwise, the viewport that instantiates it will not be able to calculate its minimum size reliably.
+ [b]Example:[/b] Use a constructed node as a tooltip:
[codeblocks]
[gdscript]
func _make_custom_tooltip(for_text):
@@ -186,7 +186,7 @@
}
[/csharp]
[/codeblocks]
- [b]Example of usage with a custom scene instance:[/b]
+ [b]Example:[/b] Usa a scene instance as a tooltip:
[codeblocks]
[gdscript]
func _make_custom_tooltip(for_text):
@@ -228,7 +228,7 @@
<description>
Creates a local override for a theme [Color] with the specified [param name]. Local overrides always take precedence when fetching theme items for the control. An override can be removed with [method remove_theme_color_override].
See also [method get_theme_color].
- [b]Example of overriding a label's color and resetting it later:[/b]
+ [b]Example:[/b] Override a [Label]'s color and reset it later:
[codeblocks]
[gdscript]
# Given the child Label node "MyLabel", override its font color with a custom value.
@@ -292,10 +292,10 @@
<description>
Creates a local override for a theme [StyleBox] with the specified [param name]. Local overrides always take precedence when fetching theme items for the control. An override can be removed with [method remove_theme_stylebox_override].
See also [method get_theme_stylebox].
- [b]Example of modifying a property in a StyleBox by duplicating it:[/b]
+ [b]Example:[/b] Modify a property in a [StyleBox] by duplicating it:
[codeblocks]
[gdscript]
- # The snippet below assumes the child node MyButton has a StyleBoxFlat assigned.
+ # The snippet below assumes the child node "MyButton" has a StyleBoxFlat assigned.
# Resources are shared across instances, so we need to duplicate it
# to avoid modifying the appearance of all other buttons.
var new_stylebox_normal = $MyButton.get_theme_stylebox("normal").duplicate()
@@ -306,7 +306,7 @@
$MyButton.remove_theme_stylebox_override("normal")
[/gdscript]
[csharp]
- // The snippet below assumes the child node MyButton has a StyleBoxFlat assigned.
+ // The snippet below assumes the child node "MyButton" has a StyleBoxFlat assigned.
// Resources are shared across instances, so we need to duplicate it
// to avoid modifying the appearance of all other buttons.
StyleBoxFlat newStyleboxNormal = GetNode&lt;Button&gt;("MyButton").GetThemeStylebox("normal").Duplicate() as StyleBoxFlat;
@@ -446,7 +446,7 @@
<description>
Returns the position of this [Control] in global screen coordinates (i.e. taking window position into account). Mostly useful for editor plugins.
Equals to [member global_position] if the window is embedded (see [member Viewport.gui_embed_subwindows]).
- [b]Example usage for showing a popup:[/b]
+ [b]Example:[/b] Show a popup at the mouse position:
[codeblock]
popup_menu.position = get_screen_position() + get_local_mouse_position()
popup_menu.reset_size()
@@ -559,7 +559,7 @@
<method name="grab_click_focus">
<return type="void" />
<description>
- Creates an [InputEventMouseButton] that attempts to click the control. If the event is received, the control acquires focus.
+ Creates an [InputEventMouseButton] that attempts to click the control. If the event is received, the control gains focus.
[codeblocks]
[gdscript]
func _process(delta):
@@ -809,9 +809,11 @@
<param index="1" name="can_drop_func" type="Callable" />
<param index="2" name="drop_func" type="Callable" />
<description>
- Forwards the handling of this control's [method _get_drag_data], [method _can_drop_data] and [method _drop_data] virtual functions to delegate callables.
- For each argument, if not empty, the delegate callable is used, otherwise the local (virtual) function is used.
- The function format for each callable should be exactly the same as the virtual functions described above.
+ Sets the given callables to be used instead of the control's own drag-and-drop virtual methods. If a callable is empty, its respective virtual method is used as normal.
+ The arguments for each callable should be exactly the same as their respective virtual methods, which would be:
+ - [param drag_func] corresponds to [method _get_drag_data] and requires a [Vector2];
+ - [param can_drop_func] corresponds to [method _can_drop_data] and requires both a [Vector2] and a [Variant];
+ - [param drop_func] corresponds to [method _drop_data] and requires both a [Vector2] and a [Variant].
</description>
</method>
<method name="set_drag_preview">
diff --git a/doc/classes/Curve3D.xml b/doc/classes/Curve3D.xml
index 9157649af2..f8386b73b2 100644
--- a/doc/classes/Curve3D.xml
+++ b/doc/classes/Curve3D.xml
@@ -204,6 +204,9 @@
<member name="bake_interval" type="float" setter="set_bake_interval" getter="get_bake_interval" default="0.2">
The distance in meters between two adjacent cached points. Changing it forces the cache to be recomputed the next time the [method get_baked_points] or [method get_baked_length] function is called. The smaller the distance, the more points in the cache and the more memory it will consume, so use with care.
</member>
+ <member name="closed" type="bool" setter="set_closed" getter="is_closed" default="false">
+ If [code]true[/code], and the curve has more than 2 control points, the last point and the first one will be connected in a loop.
+ </member>
<member name="point_count" type="int" setter="set_point_count" getter="get_point_count" default="0">
The number of points describing the curve.
</member>
diff --git a/doc/classes/DirAccess.xml b/doc/classes/DirAccess.xml
index dcd2d527e2..0f5844fd63 100644
--- a/doc/classes/DirAccess.xml
+++ b/doc/classes/DirAccess.xml
@@ -14,7 +14,7 @@
# Static
DirAccess.make_dir_absolute("user://levels/world1")
[/codeblock]
- [b]Note:[/b] Many resources types are imported (e.g. textures or sound files), and their source asset will not be included in the exported game, as only the imported version is used. Use [ResourceLoader] to access imported resources.
+ [b]Note:[/b] Accessing project ("res://") directories once exported may behave unexpectedly as some files are converted to engine-specific formats and their original source files may not be present in the expected PCK package. Because of this, to access resources in an exported project, it is recommended to use [ResourceLoader] instead of [FileAccess].
Here is an example on how to iterate through the files of a directory:
[codeblocks]
[gdscript]
@@ -116,6 +116,7 @@
<param index="0" name="path" type="String" />
<description>
Returns whether the target directory exists. The argument can be relative to the current directory, or an absolute path.
+ [b]Note:[/b] The returned [bool] in the editor and after exporting when used on a path in the [code]res://[/code] directory may be different. Some files are converted to engine-specific formats when exported, potentially changing the directory structure.
</description>
</method>
<method name="dir_exists_absolute" qualifiers="static">
@@ -123,6 +124,7 @@
<param index="0" name="path" type="String" />
<description>
Static version of [method dir_exists]. Supports only absolute paths.
+ [b]Note:[/b] The returned [bool] in the editor and after exporting when used on a path in the [code]res://[/code] directory may be different. Some files are converted to engine-specific formats when exported, potentially changing the directory structure.
</description>
</method>
<method name="file_exists">
@@ -131,6 +133,7 @@
<description>
Returns whether the target file exists. The argument can be relative to the current directory, or an absolute path.
For a static equivalent, use [method FileAccess.file_exists].
+ [b]Note:[/b] Many resources types are imported (e.g. textures or sound files), and their source asset will not be included in the exported game, as only the imported version is used. See [method ResourceLoader.exists] for an alternative approach that takes resource remapping into account.
</description>
</method>
<method name="get_current_dir" qualifiers="const">
@@ -151,6 +154,7 @@
<description>
Returns a [PackedStringArray] containing filenames of the directory contents, excluding files. The array is sorted alphabetically.
Affected by [member include_hidden] and [member include_navigational].
+ [b]Note:[/b] The returned directories in the editor and after exporting in the [code]res://[/code] directory may differ as some files are converted to engine-specific formats when exported.
</description>
</method>
<method name="get_directories_at" qualifiers="static">
@@ -159,6 +163,7 @@
<description>
Returns a [PackedStringArray] containing filenames of the directory contents, excluding files, at the given [param path]. The array is sorted alphabetically.
Use [method get_directories] if you want more control of what gets included.
+ [b]Note:[/b] The returned directories in the editor and after exporting in the [code]res://[/code] directory may differ as some files are converted to engine-specific formats when exported.
</description>
</method>
<method name="get_drive_count" qualifiers="static">
@@ -194,6 +199,7 @@
<description>
Returns a [PackedStringArray] containing filenames of the directory contents, excluding directories, at the given [param path]. The array is sorted alphabetically.
Use [method get_files] if you want more control of what gets included.
+ [b]Note:[/b] When used on a [code]res://[/code] path in an exported project, only the files included in the PCK at the given folder level are returned. In practice, this means that since imported resources are stored in a top-level [code].godot/[/code] folder, only paths to [code].gd[/code] and [code].import[/code] files are returned (plus a few other files, such as [code]project.godot[/code] or [code]project.binary[/code] and the project icon). In an exported project, the list of returned files will also vary depending on [member ProjectSettings.editor/export/convert_text_resources_to_binary].
</description>
</method>
<method name="get_next">
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index dafa86d42e..e2a352de9a 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -237,7 +237,7 @@
<return type="int" />
<param index="0" name="rect" type="Rect2" />
<description>
- Returns index of the screen which contains specified rectangle.
+ Returns the index of the screen that overlaps the most with the given rectangle. Returns [code]-1[/code] if the rectangle doesn't overlap with any screen or has no area.
</description>
</method>
<method name="get_swap_cancel_ok">
diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml
index e5f3010366..186f249281 100644
--- a/doc/classes/EditorImportPlugin.xml
+++ b/doc/classes/EditorImportPlugin.xml
@@ -154,7 +154,7 @@
<param index="1" name="option_name" type="StringName" />
<param index="2" name="options" type="Dictionary" />
<description>
- This method can be overridden to hide specific import options if conditions are met. This is mainly useful for hiding options that depend on others if one of them is disabled. For example:
+ This method can be overridden to hide specific import options if conditions are met. This is mainly useful for hiding options that depend on others if one of them is disabled.
[codeblocks]
[gdscript]
func _get_option_visibility(option, options):
diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml
index 0304499a61..624e828520 100644
--- a/doc/classes/EditorInterface.xml
+++ b/doc/classes/EditorInterface.xml
@@ -117,6 +117,12 @@
[b]Note:[/b] When creating custom editor UI, prefer accessing theme items directly from your GUI nodes using the [code]get_theme_*[/code] methods.
</description>
</method>
+ <method name="get_editor_toaster" qualifiers="const">
+ <return type="EditorToaster" />
+ <description>
+ Returns the editor's [EditorToaster].
+ </description>
+ </method>
<method name="get_editor_undo_redo" qualifiers="const">
<return type="EditorUndoRedoManager" />
<description>
diff --git a/doc/classes/EditorNode3DGizmoPlugin.xml b/doc/classes/EditorNode3DGizmoPlugin.xml
index 8fd7c167d9..6a91e3559d 100644
--- a/doc/classes/EditorNode3DGizmoPlugin.xml
+++ b/doc/classes/EditorNode3DGizmoPlugin.xml
@@ -54,7 +54,7 @@
<return type="EditorNode3DGizmo" />
<param index="0" name="for_node_3d" type="Node3D" />
<description>
- Override this method to return a custom [EditorNode3DGizmo] for the spatial nodes of your choice, return [code]null[/code] for the rest of nodes. See also [method _has_gizmo].
+ Override this method to return a custom [EditorNode3DGizmo] for the 3D nodes of your choice, return [code]null[/code] for the rest of nodes. See also [method _has_gizmo].
</description>
</method>
<method name="_get_gizmo_name" qualifiers="virtual const">
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index 8189f253fb..2cc9e08dd3 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -416,7 +416,7 @@
<param index="1" name="title" type="String" />
<param index="2" name="shortcut" type="Shortcut" default="null" />
<description>
- Adds a control to the bottom panel (together with Output, Debug, Animation, etc). Returns a reference to the button added. It's up to you to hide/show the button when needed. When your plugin is deactivated, make sure to remove your custom control with [method remove_control_from_bottom_panel] and free it with [method Node.queue_free].
+ Adds a control to the bottom panel (together with Output, Debug, Animation, etc.). Returns a reference to the button added. It's up to you to hide/show the button when needed. When your plugin is deactivated, make sure to remove your custom control with [method remove_control_from_bottom_panel] and free it with [method Node.queue_free].
Optionally, you can specify a shortcut parameter. When pressed, this shortcut will toggle the bottom panel's visibility. See the default editor bottom panel shortcuts in the Editor Settings for inspiration. Per convention, they all use [kbd]Alt[/kbd] modifier.
</description>
</method>
diff --git a/doc/classes/EditorResourcePreviewGenerator.xml b/doc/classes/EditorResourcePreviewGenerator.xml
index 9c9b6d11b2..89bfe836d7 100644
--- a/doc/classes/EditorResourcePreviewGenerator.xml
+++ b/doc/classes/EditorResourcePreviewGenerator.xml
@@ -4,7 +4,7 @@
Custom generator of previews.
</brief_description>
<description>
- Custom code to generate previews. Please check [code]file_dialog/thumbnail_size[/code] in [EditorSettings] to find out the right size to do previews at.
+ Custom code to generate previews. Check [member EditorSettings.filesystem/file_dialog/thumbnail_size] to find a proper size to generate previews at.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/EditorScenePostImport.xml b/doc/classes/EditorScenePostImport.xml
index 7325d31fc5..f8938c459c 100644
--- a/doc/classes/EditorScenePostImport.xml
+++ b/doc/classes/EditorScenePostImport.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Imported scenes can be automatically modified right after import by setting their [b]Custom Script[/b] Import property to a [code]tool[/code] script that inherits from this class.
- The [method _post_import] callback receives the imported scene's root node and returns the modified version of the scene. Usage example:
+ The [method _post_import] callback receives the imported scene's root node and returns the modified version of the scene:
[codeblocks]
[gdscript]
@tool # Needed so it runs in editor.
diff --git a/doc/classes/EditorScript.xml b/doc/classes/EditorScript.xml
index bd18852dbc..e342966fe8 100644
--- a/doc/classes/EditorScript.xml
+++ b/doc/classes/EditorScript.xml
@@ -6,7 +6,7 @@
<description>
Scripts extending this class and implementing its [method _run] method can be executed from the Script Editor's [b]File &gt; Run[/b] menu option (or by pressing [kbd]Ctrl + Shift + X[/kbd]) while the editor is running. This is useful for adding custom in-editor functionality to Godot. For more complex additions, consider using [EditorPlugin]s instead.
[b]Note:[/b] Extending scripts need to have [code]tool[/code] mode enabled.
- [b]Example script:[/b]
+ [b]Example:[/b] Running the following script prints "Hello from the Godot Editor!":
[codeblocks]
[gdscript]
@tool
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 116b6573f2..ea987da6f5 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -359,7 +359,7 @@
<member name="editors/3d/navigation/navigation_scheme" type="int" setter="" getter="">
The navigation scheme preset to use in the 3D editor. Changing this setting will affect the mouse button and modifier controls used to navigate the 3D editor viewport.
All schemes can use [kbd]Mouse wheel[/kbd] to zoom.
- - [b]Godot:[/b] [kbd]Middle mouse button[/kbd] to orbit. [kbd]Shift + Middle mouse button[/kbd] to pan. [kbd]Ctrl + Shift + Middle mouse button[/kbd] to zoom.
+ - [b]Godot:[/b] [kbd]Middle mouse button[/kbd] to orbit. [kbd]Shift + Middle mouse button[/kbd] to pan. [kbd]Ctrl + Middle mouse button[/kbd] to zoom.
- [b]Maya:[/b] [kbd]Alt + Left mouse button[/kbd] to orbit. [kbd]Middle mouse button[/kbd] to pan, [kbd]Shift + Middle mouse button[/kbd] to pan 10 times faster. [kbd]Alt + Right mouse button[/kbd] to zoom.
- [b]Modo:[/b] [kbd]Alt + Left mouse button[/kbd] to orbit. [kbd]Alt + Shift + Left mouse button[/kbd] to pan. [kbd]Ctrl + Alt + Left mouse button[/kbd] to zoom.
See also [member editors/3d/navigation/orbit_mouse_button], [member editors/3d/navigation/pan_mouse_button], [member editors/3d/navigation/zoom_mouse_button], and [member editors/3d/freelook/freelook_navigation_scheme].
@@ -1275,7 +1275,7 @@
If [code]true[/code], adds [url=$DOCS_URL/tutorials/scripting/gdscript/static_typing.html]GDScript static typing[/url] hints such as [code]-&gt; void[/code] and [code]: int[/code] when using code autocompletion or when creating onready variables by drag and dropping nodes into the script editor while pressing the [kbd]Ctrl[/kbd] key. If [code]true[/code], newly created scripts will also automatically have type hints added to their method parameters and return types.
</member>
<member name="text_editor/completion/auto_brace_complete" type="bool" setter="" getter="">
- If [code]true[/code], automatically completes braces when making use of code completion.
+ If [code]true[/code], automatically inserts the matching closing brace when the opening brace is inserted by typing or autocompletion. Also automatically removes the closing brace when pressing [kbd]Backspace[/kbd] on the opening brace. This includes brackets ([code]()[/code], [code][][/code], [code]{}[/code]), string quotation marks ([code]''[/code], [code]""[/code]), and comments ([code]/**/[/code]) if the language supports it.
</member>
<member name="text_editor/completion/code_complete_delay" type="float" setter="" getter="">
The delay in seconds after which autocompletion suggestions should be displayed when the user stops typing.
@@ -1328,6 +1328,9 @@
<member name="text_editor/script_list/group_help_pages" type="bool" setter="" getter="">
If [code]true[/code], class reference pages are grouped together at the bottom of the Script Editor's script list.
</member>
+ <member name="text_editor/script_list/highlight_scene_scripts" type="bool" setter="" getter="">
+ If [code]true[/code], the scripts that are used by the current scene are highlighted in the Script Editor's script list.
+ </member>
<member name="text_editor/script_list/list_script_names_as" type="int" setter="" getter="">
Specifies how script paths should be displayed in Script Editor's script list. If using the "Name" option and some scripts share the same file name, more parts of their paths are revealed to avoid conflicts.
</member>
diff --git a/doc/classes/EditorSpinSlider.xml b/doc/classes/EditorSpinSlider.xml
index 83c65b736e..6cd375a46d 100644
--- a/doc/classes/EditorSpinSlider.xml
+++ b/doc/classes/EditorSpinSlider.xml
@@ -40,6 +40,11 @@
Emitted when the spinner/slider is ungrabbed.
</description>
</signal>
+ <signal name="updown_pressed">
+ <description>
+ Emitted when the updown button is pressed.
+ </description>
+ </signal>
<signal name="value_focus_entered">
<description>
Emitted when the value form gains focus.
diff --git a/doc/classes/EditorToaster.xml b/doc/classes/EditorToaster.xml
new file mode 100644
index 0000000000..c30b94c989
--- /dev/null
+++ b/doc/classes/EditorToaster.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="EditorToaster" inherits="HBoxContainer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Manages toast notifications within the editor.
+ </brief_description>
+ <description>
+ This object manages the functionality and display of toast notifications within the editor, ensuring timely and informative alerts are presented to users.
+ [b]Note:[/b] This class shouldn't be instantiated directly. Instead, access the singleton using [method EditorInterface.get_editor_toaster].
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="push_toast">
+ <return type="void" />
+ <param index="0" name="message" type="String" />
+ <param index="1" name="severity" type="int" enum="EditorToaster.Severity" default="0" />
+ <param index="2" name="tooltip" type="String" default="&quot;&quot;" />
+ <description>
+ Pushes a toast notification to the editor for display.
+ </description>
+ </method>
+ </methods>
+ <constants>
+ <constant name="SEVERITY_INFO" value="0" enum="Severity">
+ Toast will display with an INFO severity.
+ </constant>
+ <constant name="SEVERITY_WARNING" value="1" enum="Severity">
+ Toast will display with a WARNING severity and have a corresponding color.
+ </constant>
+ <constant name="SEVERITY_ERROR" value="2" enum="Severity">
+ Toast will display with an ERROR severity and have a corresponding color.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/EditorTranslationParserPlugin.xml b/doc/classes/EditorTranslationParserPlugin.xml
index a47a41594e..b9dc654de3 100644
--- a/doc/classes/EditorTranslationParserPlugin.xml
+++ b/doc/classes/EditorTranslationParserPlugin.xml
@@ -69,8 +69,7 @@
msgidsContextPlural.Add(new Godot.Collections.Array{"Only with context", "a friendly context", ""});
[/csharp]
[/codeblocks]
- [b]Note:[/b] If you override parsing logic for standard script types (GDScript, C#, etc.), it would be better to load the [code]path[/code] argument using [method ResourceLoader.load]. This is because built-in scripts are loaded as [Resource] type, not [FileAccess] type.
- For example:
+ [b]Note:[/b] If you override parsing logic for standard script types (GDScript, C#, etc.), it would be better to load the [code]path[/code] argument using [method ResourceLoader.load]. This is because built-in scripts are loaded as [Resource] type, not [FileAccess] type. For example:
[codeblocks]
[gdscript]
func _parse_file(path, msgids, msgids_context_plural):
@@ -100,6 +99,14 @@
<tutorials>
</tutorials>
<methods>
+ <method name="_get_comments" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="msgids_comment" type="String[]" />
+ <param index="1" name="msgids_context_plural_comment" type="String[]" />
+ <description>
+ If overridden, called after [method _parse_file] to get comments for the parsed entries. This method should fill the arrays with the same number of elements and in the same order as [method _parse_file].
+ </description>
+ </method>
<method name="_get_recognized_extensions" qualifiers="virtual const">
<return type="PackedStringArray" />
<description>
diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml
index bba5157053..3ae3753930 100644
--- a/doc/classes/Engine.xml
+++ b/doc/classes/Engine.xml
@@ -13,21 +13,7 @@
<return type="String" />
<description>
Returns the name of the CPU architecture the Godot binary was built for. Possible return values include [code]"x86_64"[/code], [code]"x86_32"[/code], [code]"arm64"[/code], [code]"arm32"[/code], [code]"rv64"[/code], [code]"riscv"[/code], [code]"ppc64"[/code], [code]"ppc"[/code], [code]"wasm64"[/code], and [code]"wasm32"[/code].
- To detect whether the current build is 64-bit, you can use the fact that all 64-bit architecture names contain [code]64[/code] in their name:
- [codeblocks]
- [gdscript]
- if "64" in Engine.get_architecture_name():
- print("Running a 64-bit build of Godot.")
- else:
- print("Running a 32-bit build of Godot.")
- [/gdscript]
- [csharp]
- if (Engine.GetArchitectureName().Contains("64"))
- GD.Print("Running a 64-bit build of Godot.");
- else
- GD.Print("Running a 32-bit build of Godot.");
- [/csharp]
- [/codeblocks]
+ To detect whether the current build is 64-bit, or the type of architecture, don't use the architecture name. Instead, use [method OS.has_feature] to check for the [code]"64"[/code] feature tag, or tags such as [code]"x86"[/code] or [code]"arm"[/code]. See the [url=$DOCS_URL/tutorials/export/feature_tags.html]Feature Tags[/url] documentation for more details.
[b]Note:[/b] This method does [i]not[/i] return the name of the system's CPU architecture (like [method OS.get_processor_name]). For example, when running an [code]x86_32[/code] Godot binary on an [code]x86_64[/code] system, the returned value will still be [code]"x86_32"[/code].
</description>
</method>
diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml
index 1779408a4d..47fc48305b 100644
--- a/doc/classes/Environment.xml
+++ b/doc/classes/Environment.xml
@@ -182,7 +182,8 @@
[b]Note:[/b] [member glow_map] has no effect when using the Compatibility rendering method, due to this rendering method using a simpler glow implementation optimized for low-end devices.
</member>
<member name="glow_map_strength" type="float" setter="set_glow_map_strength" getter="get_glow_map_strength" default="0.8">
- How strong of an impact the [member glow_map] should have on the overall glow effect. A strength of [code]0.0[/code] means the glow map has no effect on the overall glow effect. A strength of [code]1.0[/code] means the glow has a full effect on the overall glow effect (and can turn off glow entirely in specific areas of the screen if the glow map has black areas).
+ How strong of an influence the [member glow_map] should have on the overall glow effect. A strength of [code]0.0[/code] means the glow map has no influence, while a strength of [code]1.0[/code] means the glow map has full influence.
+ [b]Note:[/b] If the glow map has black areas, a value of [code]1.0[/code] can also turn off the glow effect entirely in specific areas of the screen.
[b]Note:[/b] [member glow_map_strength] has no effect when using the Compatibility rendering method, due to this rendering method using a simpler glow implementation optimized for low-end devices.
</member>
<member name="glow_mix" type="float" setter="set_glow_mix" getter="get_glow_mix" default="0.05">
diff --git a/doc/classes/FileAccess.xml b/doc/classes/FileAccess.xml
index b782937a8a..846897a463 100644
--- a/doc/classes/FileAccess.xml
+++ b/doc/classes/FileAccess.xml
@@ -4,7 +4,7 @@
Provides methods for file reading and writing operations.
</brief_description>
<description>
- This class can be used to permanently store data in the user device's file system and to read from it. This is useful for store game save data or player configuration files.
+ This class can be used to permanently store data in the user device's file system and to read from it. This is useful for storing game save data or player configuration files.
Here's a sample on how to write and read from a file:
[codeblocks]
[gdscript]
@@ -173,6 +173,12 @@
Returns the next 32 bits from the file as a floating-point number.
</description>
</method>
+ <method name="get_half" qualifiers="const">
+ <return type="float" />
+ <description>
+ Returns the next 16 bits from the file as a half-precision floating-point number.
+ </description>
+ </method>
<method name="get_hidden_attribute" qualifiers="static">
<return type="bool" />
<param index="0" name="file" type="String" />
@@ -308,6 +314,7 @@
<param index="0" name="path" type="String" />
<param index="1" name="mode_flags" type="int" enum="FileAccess.ModeFlags" />
<param index="2" name="key" type="PackedByteArray" />
+ <param index="3" name="iv" type="PackedByteArray" default="PackedByteArray()" />
<description>
Creates a new [FileAccess] object and opens an encrypted file in write or read mode. You need to pass a binary key to encrypt/decrypt it.
[b]Note:[/b] The provided key must be 32 bytes long.
@@ -470,6 +477,13 @@
Stores a floating-point number as 32 bits in the file.
</description>
</method>
+ <method name="store_half">
+ <return type="void" />
+ <param index="0" name="value" type="float" />
+ <description>
+ Stores a half-precision floating-point number as 16 bits in the file.
+ </description>
+ </method>
<method name="store_line">
<return type="void" />
<param index="0" name="line" type="String" />
diff --git a/doc/classes/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml
index 3c48f5ba31..96232f4277 100644
--- a/doc/classes/GPUParticles2D.xml
+++ b/doc/classes/GPUParticles2D.xml
@@ -136,7 +136,7 @@
<signal name="finished">
<description>
Emitted when all active particles have finished processing. To immediately restart the emission cycle, call [method restart].
- Never emitted when [member one_shot] is disabled, as particles will be emitted and processed continuously.
+ This signal is never emitted when [member one_shot] is disabled, as particles will be emitted and processed continuously.
[b]Note:[/b] For [member one_shot] emitters, due to the particles being computed on the GPU, there may be a short period after receiving the signal during which setting [member emitting] to [code]true[/code] will not restart the emission cycle. This delay is avoided by instead calling [method restart].
</description>
</signal>
diff --git a/doc/classes/GPUParticles3D.xml b/doc/classes/GPUParticles3D.xml
index 61a3b467f1..f5df857391 100644
--- a/doc/classes/GPUParticles3D.xml
+++ b/doc/classes/GPUParticles3D.xml
@@ -160,8 +160,8 @@
<signals>
<signal name="finished">
<description>
- Emitted when all active particles have finished processing. To immediately emit new particles, call [method restart].
- Never emitted when [member one_shot] is disabled, as particles will be emitted and processed continuously.
+ Emitted when all active particles have finished processing. To immediately restart the emission cycle, call [method restart].
+ This signal is never emitted when [member one_shot] is disabled, as particles will be emitted and processed continuously.
[b]Note:[/b] For [member one_shot] emitters, due to the particles being computed on the GPU, there may be a short period after receiving the signal during which setting [member emitting] to [code]true[/code] will not restart the emission cycle. This delay is avoided by instead calling [method restart].
</description>
</signal>
diff --git a/doc/classes/GPUParticlesCollision3D.xml b/doc/classes/GPUParticlesCollision3D.xml
index 089747b7ee..2d398edd5e 100644
--- a/doc/classes/GPUParticlesCollision3D.xml
+++ b/doc/classes/GPUParticlesCollision3D.xml
@@ -16,8 +16,8 @@
<members>
<member name="cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="4294967295">
The particle rendering layers ([member VisualInstance3D.layers]) that will be affected by the collision shape. By default, all particles that have [member ParticleProcessMaterial.collision_mode] set to [constant ParticleProcessMaterial.COLLISION_RIGID] or [constant ParticleProcessMaterial.COLLISION_HIDE_ON_CONTACT] will be affected by a collision shape.
- After configuring particle nodes accordingly, specific layers can be unchecked to prevent certain particles from being affected by attractors. For example, this can be used if you're using an attractor as part of a spell effect but don't want the attractor to affect unrelated weather particles at the same position.
- Particle attraction can also be disabled on a per-process material basis by setting [member ParticleProcessMaterial.attractor_interaction_enabled] on the [GPUParticles3D] node.
+ After configuring particle nodes accordingly, specific layers can be unchecked to prevent certain particles from being affected by colliders. For example, this can be used if you're using a collider as part of a spell effect but don't want the collider to affect unrelated weather particles at the same position.
+ Particle collision can also be disabled on a per-process material basis by setting [member ParticleProcessMaterial.collision_mode] on the [GPUParticles3D] node.
</member>
</members>
</class>
diff --git a/doc/classes/GeometryInstance3D.xml b/doc/classes/GeometryInstance3D.xml
index f4075af186..0c45154c8a 100644
--- a/doc/classes/GeometryInstance3D.xml
+++ b/doc/classes/GeometryInstance3D.xml
@@ -39,8 +39,12 @@
<member name="extra_cull_margin" type="float" setter="set_extra_cull_margin" getter="get_extra_cull_margin" default="0.0">
The extra distance added to the GeometryInstance3D's bounding box ([AABB]) to increase its cull box.
</member>
- <member name="gi_lightmap_scale" type="int" setter="set_lightmap_scale" getter="get_lightmap_scale" enum="GeometryInstance3D.LightmapScale" default="0">
+ <member name="gi_lightmap_scale" type="int" setter="set_lightmap_scale" getter="get_lightmap_scale" enum="GeometryInstance3D.LightmapScale" default="0" deprecated="Use [member gi_lightmap_texel_scale] instead.">
+ The texel density to use for lightmapping in [LightmapGI].
+ </member>
+ <member name="gi_lightmap_texel_scale" type="float" setter="set_lightmap_texel_scale" getter="get_lightmap_texel_scale" default="1.0">
The texel density to use for lightmapping in [LightmapGI]. Greater scale values provide higher resolution in the lightmap, which can result in sharper shadows for lights that have both direct and indirect light baked. However, greater scale values will also increase the space taken by the mesh in the lightmap texture, which increases the memory, storage, and bake time requirements. When using a single mesh at different scales, consider adjusting this value to keep the lightmap texel density consistent across meshes.
+ For example, doubling [member gi_lightmap_texel_scale] doubles the lightmap texture resolution for this object [i]on each axis[/i], so it will [i]quadruple[/i] the texel count.
</member>
<member name="gi_mode" type="int" setter="set_gi_mode" getter="get_gi_mode" enum="GeometryInstance3D.GIMode" default="1" keywords="global_illumination_mode, light_bake_mode">
The global illumination mode to use for the whole geometry. To avoid inconsistent results, use a mode that matches the purpose of the mesh during gameplay (static/dynamic).
@@ -111,19 +115,19 @@
<constant name="GI_MODE_DYNAMIC" value="2" enum="GIMode">
Dynamic global illumination mode. Use for dynamic objects that contribute to global illumination. This GI mode is only effective when using [VoxelGI], but it has a higher performance impact than [constant GI_MODE_STATIC]. When using other GI methods, this will act the same as [constant GI_MODE_DISABLED]. When using [LightmapGI], the object will receive indirect lighting using lightmap probes instead of using the baked lightmap texture.
</constant>
- <constant name="LIGHTMAP_SCALE_1X" value="0" enum="LightmapScale">
+ <constant name="LIGHTMAP_SCALE_1X" value="0" enum="LightmapScale" deprecated="Use [member gi_lightmap_texel_scale] instead.">
The standard texel density for lightmapping with [LightmapGI].
</constant>
- <constant name="LIGHTMAP_SCALE_2X" value="1" enum="LightmapScale">
+ <constant name="LIGHTMAP_SCALE_2X" value="1" enum="LightmapScale" deprecated="Use [member gi_lightmap_texel_scale] instead.">
Multiplies texel density by 2× for lightmapping with [LightmapGI]. To ensure consistency in texel density, use this when scaling a mesh by a factor between 1.5 and 3.0.
</constant>
- <constant name="LIGHTMAP_SCALE_4X" value="2" enum="LightmapScale">
+ <constant name="LIGHTMAP_SCALE_4X" value="2" enum="LightmapScale" deprecated="Use [member gi_lightmap_texel_scale] instead.">
Multiplies texel density by 4× for lightmapping with [LightmapGI]. To ensure consistency in texel density, use this when scaling a mesh by a factor between 3.0 and 6.0.
</constant>
- <constant name="LIGHTMAP_SCALE_8X" value="3" enum="LightmapScale">
+ <constant name="LIGHTMAP_SCALE_8X" value="3" enum="LightmapScale" deprecated="Use [member gi_lightmap_texel_scale] instead.">
Multiplies texel density by 8× for lightmapping with [LightmapGI]. To ensure consistency in texel density, use this when scaling a mesh by a factor greater than 6.0.
</constant>
- <constant name="LIGHTMAP_SCALE_MAX" value="4" enum="LightmapScale">
+ <constant name="LIGHTMAP_SCALE_MAX" value="4" enum="LightmapScale" deprecated="Use [member gi_lightmap_texel_scale] instead.">
Represents the size of the [enum LightmapScale] enum.
</constant>
<constant name="VISIBILITY_RANGE_FADE_DISABLED" value="0" enum="VisibilityRangeFadeMode">
diff --git a/doc/classes/HTTPClient.xml b/doc/classes/HTTPClient.xml
index af98636056..366038e43f 100644
--- a/doc/classes/HTTPClient.xml
+++ b/doc/classes/HTTPClient.xml
@@ -277,7 +277,11 @@
HTTP status code [code]102 Processing[/code] (WebDAV). Indicates that the server has received and is processing the request, but no response is available yet.
</constant>
<constant name="RESPONSE_OK" value="200" enum="ResponseCode">
- HTTP status code [code]200 OK[/code]. The request has succeeded. Default response for successful requests. Meaning varies depending on the request. GET: The resource has been fetched and is transmitted in the message body. HEAD: The entity headers are in the message body. POST: The resource describing the result of the action is transmitted in the message body. TRACE: The message body contains the request message as received by the server.
+ HTTP status code [code]200 OK[/code]. The request has succeeded. Default response for successful requests. Meaning varies depending on the request:
+ - [constant METHOD_GET]: The resource has been fetched and is transmitted in the message body.
+ - [constant METHOD_HEAD]: The entity headers are in the message body.
+ - [constant METHOD_POST]: The resource describing the result of the action is transmitted in the message body.
+ - [constant METHOD_TRACE]: The message body contains the request message as received by the server.
</constant>
<constant name="RESPONSE_CREATED" value="201" enum="ResponseCode">
HTTP status code [code]201 Created[/code]. The request has succeeded and a new resource has been created as a result of it. This is typically the response sent after a PUT request.
diff --git a/doc/classes/HTTPRequest.xml b/doc/classes/HTTPRequest.xml
index a4adf4d1b1..36f5e82652 100644
--- a/doc/classes/HTTPRequest.xml
+++ b/doc/classes/HTTPRequest.xml
@@ -8,7 +8,7 @@
Can be used to make HTTP requests, i.e. download or upload files or web content via HTTP.
[b]Warning:[/b] See the notes and warnings on [HTTPClient] for limitations, especially regarding TLS security.
[b]Note:[/b] When exporting to Android, make sure to enable the [code]INTERNET[/code] permission in the Android export preset before exporting the project or using one-click deploy. Otherwise, network communication of any kind will be blocked by Android.
- [b]Example of contacting a REST API and printing one of its returned fields:[/b]
+ [b]Example:[/b] Contact a REST API and print one of its returned fields:
[codeblocks]
[gdscript]
func _ready():
@@ -80,7 +80,7 @@
}
[/csharp]
[/codeblocks]
- [b]Example of loading and displaying an image using HTTPRequest:[/b]
+ [b]Example:[/b] Load an image using [HTTPRequest] and display it:
[codeblocks]
[gdscript]
func _ready():
@@ -150,7 +150,7 @@
}
[/csharp]
[/codeblocks]
- [b]Gzipped response bodies[/b]: HTTPRequest will automatically handle decompression of response bodies. A [code]Accept-Encoding[/code] header will be automatically added to each of your requests, unless one is already specified. Any response with a [code]Content-Encoding: gzip[/code] header will automatically be decompressed and delivered to you as uncompressed bytes.
+ [b]Note:[/b] [HTTPRequest] nodes will automatically handle decompression of response bodies. A [code]Accept-Encoding[/code] header will be automatically added to each of your requests, unless one is already specified. Any response with a [code]Content-Encoding: gzip[/code] header will automatically be decompressed and delivered to you as uncompressed bytes.
</description>
<tutorials>
<link title="Making HTTP requests">$DOCS_URL/tutorials/networking/http_request_class.html</link>
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index 9b71a8c37f..4421318be7 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -48,6 +48,7 @@
<param index="2" name="dst" type="Vector2i" />
<description>
Copies [param src_rect] from [param src] image to this image at coordinates [param dst], clipped accordingly to both image bounds. This image and [param src] image [b]must[/b] have the same format. [param src_rect] with non-positive size is treated as empty.
+ [b]Note:[/b] The alpha channel data in [param src] will overwrite the corresponding data in this image at the target position. To blend alpha channels, use [method blend_rect] instead.
</description>
</method>
<method name="blit_rect_mask">
diff --git a/doc/classes/ItemList.xml b/doc/classes/ItemList.xml
index fdaeb54bdf..7754a61e8c 100644
--- a/doc/classes/ItemList.xml
+++ b/doc/classes/ItemList.xml
@@ -29,7 +29,7 @@
<description>
Adds an item to the item list with specified text. Returns the index of an added item.
Specify an [param icon], or use [code]null[/code] as the [param icon] for a list item with no icon.
- If selectable is [code]true[/code], the list item will be selectable.
+ If [param selectable] is [code]true[/code], the list item will be selectable.
</description>
</method>
<method name="clear">
diff --git a/doc/classes/LightmapGI.xml b/doc/classes/LightmapGI.xml
index e7d44411ef..70265443a4 100644
--- a/doc/classes/LightmapGI.xml
+++ b/doc/classes/LightmapGI.xml
@@ -10,6 +10,7 @@
[b]Note:[/b] Due to how lightmaps work, most properties only have a visible effect once lightmaps are baked again.
[b]Note:[/b] Lightmap baking on [CSGShape3D]s and [PrimitiveMesh]es is not supported, as these cannot store UV2 data required for baking.
[b]Note:[/b] If no custom lightmappers are installed, [LightmapGI] can only be baked from devices that support the Forward+ or Mobile rendering backends.
+ [b]Note:[/b] The [LightmapGI] node only bakes light data for child nodes of its parent. Nodes further up the hierarchy of the scene will not be baked.
</description>
<tutorials>
<link title="Using Lightmap global illumination">$DOCS_URL/tutorials/3d/global_illumination/using_lightmap_gi.html</link>
@@ -66,10 +67,11 @@
</member>
<member name="quality" type="int" setter="set_bake_quality" getter="get_bake_quality" enum="LightmapGI.BakeQuality" default="1">
The quality preset to use when baking lightmaps. This affects bake times, but output file sizes remain mostly identical across quality levels.
- To further speed up bake times, decrease [member bounces], disable [member use_denoiser] and increase the lightmap texel size on 3D scenes in the Import doc.
+ To further speed up bake times, decrease [member bounces], disable [member use_denoiser] and increase the lightmap texel size on 3D scenes in the Import dock.
</member>
<member name="texel_scale" type="float" setter="set_texel_scale" getter="get_texel_scale" default="1.0">
Scales the lightmap texel density of all meshes for the current bake. This is a multiplier that builds upon the existing lightmap texel size defined in each imported 3D scene, along with the per-mesh density multiplier (which is designed to be used when the same mesh is used at different scales). Lower values will result in faster bake times.
+ For example, doubling [member texel_scale] doubles the lightmap texture resolution for all objects [i]on each axis[/i], so it will [i]quadruple[/i] the texel count.
</member>
<member name="use_denoiser" type="bool" setter="set_use_denoiser" getter="is_using_denoiser" default="true">
If [code]true[/code], uses a GPU-based denoising algorithm on the generated lightmap. This eliminates most noise within the generated lightmap at the cost of longer bake times. File sizes are generally not impacted significantly by the use of a denoiser, although lossless compression may do a better job at compressing a denoised image.
diff --git a/doc/classes/LookAtModifier3D.xml b/doc/classes/LookAtModifier3D.xml
new file mode 100644
index 0000000000..2475de1868
--- /dev/null
+++ b/doc/classes/LookAtModifier3D.xml
@@ -0,0 +1,162 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="LookAtModifier3D" inherits="SkeletonModifier3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ The [LookAtModifier3D] rotates a bone to look at a target.
+ </brief_description>
+ <description>
+ This [SkeletonModifier3D] rotates a bone to look at a target. This is helpful for moving a character's head to look at the player, rotating a turret to look at a target, or any other case where you want to make a bone rotate towards something quickly and easily.
+ When applying multiple [LookAtModifier3D]s, the [LookAtModifier3D] assigned to the parent bone must be put above the [LookAtModifier3D] assigned to the child bone in the list in order for the child bone results to be correct.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_interpolation_remaining" qualifiers="const">
+ <return type="float" />
+ <description>
+ Returns the remaining seconds of the time-based interpolation.
+ </description>
+ </method>
+ <method name="is_interpolating" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns whether the time-based interpolation is running or not. If [code]true[/code], it is equivalent to [method get_interpolation_remaining] being [code]0[/code].
+ This is useful to determine whether a [LookAtModifier3D] can be removed safely.
+ </description>
+ </method>
+ <method name="is_target_within_limitation" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns whether the target is within the angle limitations. It is useful for unsetting the [member target_node] when the target is outside of the angle limitations.
+ [b]Note:[/b] The value is updated after [method SkeletonModifier3D._process_modification]. To retrieve this value correctly, we recommend using the signal [signal SkeletonModifier3D.modification_processed].
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="bone" type="int" setter="set_bone" getter="get_bone" default="-1">
+ Index of the [member bone_name] in the parent [Skeleton3D].
+ </member>
+ <member name="bone_name" type="String" setter="set_bone_name" getter="get_bone_name" default="&quot;&quot;">
+ The bone name of the [Skeleton3D] that the modification will operate on.
+ </member>
+ <member name="duration" type="float" setter="set_duration" getter="get_duration" default="0.0">
+ The duration of the time-based interpolation. Interpolation is triggered at the following cases:
+ - When the target node is changed
+ - When an axis is flipped due to angle limitation
+ [b]Note:[/b] The flipping occurs when the target is outside the angle limitation and the internally computed secondary rotation axis of the forward vector is flipped. Visually, it occurs when the target is outside the angle limitation and crosses the plane of the [member forward_axis] and [member primary_rotation_axis].
+ </member>
+ <member name="ease_type" type="int" setter="set_ease_type" getter="get_ease_type" enum="Tween.EaseType" default="0">
+ The ease type of the time-based interpolation. See also [enum Tween.EaseType].
+ </member>
+ <member name="forward_axis" type="int" setter="set_forward_axis" getter="get_forward_axis" enum="LookAtModifier3D.BoneAxis" default="4">
+ The forward axis of the bone. This [SkeletonModifier3D] modifies the bone so that this axis points toward the [member target_node].
+ </member>
+ <member name="origin_bone" type="int" setter="set_origin_bone" getter="get_origin_bone">
+ Index of the [member origin_bone_name] in the parent [Skeleton3D].
+ </member>
+ <member name="origin_bone_name" type="String" setter="set_origin_bone_name" getter="get_origin_bone_name">
+ If [member origin_from] is [constant ORIGIN_FROM_SPECIFIC_BONE], the bone global pose position specified for this is used as origin.
+ </member>
+ <member name="origin_external_node" type="NodePath" setter="set_origin_external_node" getter="get_origin_external_node">
+ If [member origin_from] is [constant ORIGIN_FROM_EXTERNAL_NODE], the global position of the [Node3D] specified for this is used as origin.
+ </member>
+ <member name="origin_from" type="int" setter="set_origin_from" getter="get_origin_from" enum="LookAtModifier3D.OriginFrom" default="0">
+ This value determines from what origin is retrieved for use in the calculation of the forward vector.
+ </member>
+ <member name="origin_offset" type="Vector3" setter="set_origin_offset" getter="get_origin_offset" default="Vector3(0, 0, 0)">
+ The offset of the bone pose origin. Matching the origins by offset is useful for cases where multiple bones must always face the same direction, such as the eyes.
+ [b]Note:[/b] This value indicates the local position of the object set in [member origin_from].
+ </member>
+ <member name="origin_safe_margin" type="float" setter="set_origin_safe_margin" getter="get_origin_safe_margin" default="0.1">
+ If the target passes through too close to the origin than this value, time-based interpolation is used even if the target is within the angular limitations, to prevent the angular velocity from becoming too high.
+ </member>
+ <member name="primary_damp_threshold" type="float" setter="set_primary_damp_threshold" getter="get_primary_damp_threshold">
+ The threshold to start damping for [member primary_limit_angle]. It provides non-linear (b-spline) interpolation, let it feel more resistance the more it rotate to the edge limit. This is useful for simulating the limits of human motion.
+ If [code]1.0[/code], no damping is performed. If [code]0.0[/code], damping is always performed.
+ </member>
+ <member name="primary_limit_angle" type="float" setter="set_primary_limit_angle" getter="get_primary_limit_angle">
+ The limit angle of the primary rotation when [member symmetry_limitation] is [code]true[/code].
+ </member>
+ <member name="primary_negative_damp_threshold" type="float" setter="set_primary_negative_damp_threshold" getter="get_primary_negative_damp_threshold">
+ The threshold to start damping for [member primary_negative_limit_angle].
+ </member>
+ <member name="primary_negative_limit_angle" type="float" setter="set_primary_negative_limit_angle" getter="get_primary_negative_limit_angle">
+ The limit angle of negative side of the primary rotation when [member symmetry_limitation] is [code]false[/code].
+ </member>
+ <member name="primary_positive_damp_threshold" type="float" setter="set_primary_positive_damp_threshold" getter="get_primary_positive_damp_threshold">
+ The threshold to start damping for [member primary_positive_limit_angle].
+ </member>
+ <member name="primary_positive_limit_angle" type="float" setter="set_primary_positive_limit_angle" getter="get_primary_positive_limit_angle">
+ The limit angle of positive side of the primary rotation when [member symmetry_limitation] is [code]false[/code].
+ </member>
+ <member name="primary_rotation_axis" type="int" setter="set_primary_rotation_axis" getter="get_primary_rotation_axis" enum="Vector3.Axis" default="1">
+ The axis of the first rotation. This [SkeletonModifier3D] works by compositing the rotation by Euler angles to prevent to rotate the [member forward_axis].
+ </member>
+ <member name="secondary_damp_threshold" type="float" setter="set_secondary_damp_threshold" getter="get_secondary_damp_threshold">
+ The threshold to start damping for [member secondary_limit_angle].
+ </member>
+ <member name="secondary_limit_angle" type="float" setter="set_secondary_limit_angle" getter="get_secondary_limit_angle">
+ The limit angle of the secondary rotation when [member symmetry_limitation] is [code]true[/code].
+ </member>
+ <member name="secondary_negative_damp_threshold" type="float" setter="set_secondary_negative_damp_threshold" getter="get_secondary_negative_damp_threshold">
+ The threshold to start damping for [member secondary_negative_limit_angle].
+ </member>
+ <member name="secondary_negative_limit_angle" type="float" setter="set_secondary_negative_limit_angle" getter="get_secondary_negative_limit_angle">
+ The limit angle of negative side of the secondary rotation when [member symmetry_limitation] is [code]false[/code].
+ </member>
+ <member name="secondary_positive_damp_threshold" type="float" setter="set_secondary_positive_damp_threshold" getter="get_secondary_positive_damp_threshold">
+ The threshold to start damping for [member secondary_positive_limit_angle].
+ </member>
+ <member name="secondary_positive_limit_angle" type="float" setter="set_secondary_positive_limit_angle" getter="get_secondary_positive_limit_angle">
+ The limit angle of positive side of the secondary rotation when [member symmetry_limitation] is [code]false[/code].
+ </member>
+ <member name="symmetry_limitation" type="bool" setter="set_symmetry_limitation" getter="is_limitation_symmetry">
+ If [code]true[/code], the limitations are spread from the bone symmetrically.
+ If [code]false[/code], the limitation can be specified separately for each side of the bone rest.
+ </member>
+ <member name="target_node" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
+ The [NodePath] to the node that is the target for the look at modification. This node is what the modification will rotate the bone to.
+ </member>
+ <member name="transition_type" type="int" setter="set_transition_type" getter="get_transition_type" enum="Tween.TransitionType" default="0">
+ The transition type of the time-based interpolation. See also [enum Tween.TransitionType].
+ </member>
+ <member name="use_angle_limitation" type="bool" setter="set_use_angle_limitation" getter="is_using_angle_limitation" default="false">
+ If [code]true[/code], limits the degree of rotation. This helps prevent the character's neck from rotating 360 degrees.
+ [b]Note:[/b] As with [AnimationTree] blending, interpolation is provided that favors [method Skeleton3D.get_bone_rest]. This means that interpolation does not select the shortest path in some cases.
+ [b]Note:[/b] Some [member transition_type] may exceed the limitations (e.g. `Back`, `Elastic`, and `Spring`). If interpolation occurs while overshooting the limitations, the result might possibly not respect the bone rest.
+ </member>
+ <member name="use_secondary_rotation" type="bool" setter="set_use_secondary_rotation" getter="is_using_secondary_rotation" default="true">
+ If [code]true[/code], provides rotation by two axes.
+ </member>
+ </members>
+ <constants>
+ <constant name="BONE_AXIS_PLUS_X" value="0" enum="BoneAxis">
+ Enumerated value for the +X axis.
+ </constant>
+ <constant name="BONE_AXIS_MINUS_X" value="1" enum="BoneAxis">
+ Enumerated value for the -X axis.
+ </constant>
+ <constant name="BONE_AXIS_PLUS_Y" value="2" enum="BoneAxis">
+ Enumerated value for the +Y axis.
+ </constant>
+ <constant name="BONE_AXIS_MINUS_Y" value="3" enum="BoneAxis">
+ Enumerated value for the -Y axis.
+ </constant>
+ <constant name="BONE_AXIS_PLUS_Z" value="4" enum="BoneAxis">
+ Enumerated value for the +Z axis.
+ </constant>
+ <constant name="BONE_AXIS_MINUS_Z" value="5" enum="BoneAxis">
+ Enumerated value for the -Z axis.
+ </constant>
+ <constant name="ORIGIN_FROM_SELF" value="0" enum="OriginFrom">
+ The bone rest position of the bone specified in [member bone] is used as origin.
+ </constant>
+ <constant name="ORIGIN_FROM_SPECIFIC_BONE" value="1" enum="OriginFrom">
+ The bone global pose position of the bone specified in [member origin_bone] is used as origin.
+ [b]Note:[/b] It is recommended that you select only the parent bone unless you are familiar with the bone processing process. The specified bone pose at the time the [LookAtModifier3D] is processed is used as a reference. In other words, if you specify a child bone and the [LookAtModifier3D] causes the child bone to move, the rendered result and direction will not match.
+ </constant>
+ <constant name="ORIGIN_FROM_EXTERNAL_NODE" value="2" enum="OriginFrom">
+ The global position of the [Node3D] specified in [member origin_external_node] is used as origin.
+ [b]Note:[/b] Same as [constant ORIGIN_FROM_SPECIFIC_BONE], when specifying a [BoneAttachment3D] with a child bone assigned, the rendered result and direction will not match.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/MainLoop.xml b/doc/classes/MainLoop.xml
index 17cc0d78d3..2d88876d24 100644
--- a/doc/classes/MainLoop.xml
+++ b/doc/classes/MainLoop.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
[MainLoop] is the abstract base class for a Godot project's game loop. It is inherited by [SceneTree], which is the default game loop implementation used in Godot projects, though it is also possible to write and use one's own [MainLoop] subclass instead of the scene tree.
- Upon the application start, a [MainLoop] implementation must be provided to the OS; otherwise, the application will exit. This happens automatically (and a [SceneTree] is created) unless a [MainLoop] [Script] is provided from the command line (with e.g. [code]godot -s my_loop.gd[/code]) or the "Main Loop Type" project setting is overwritten.
+ Upon the application start, a [MainLoop] implementation must be provided to the OS; otherwise, the application will exit. This happens automatically (and a [SceneTree] is created) unless a [MainLoop] [Script] is provided from the command line (with e.g. [code]godot -s my_loop.gd[/code]) or the [member ProjectSettings.application/run/main_loop_type] project setting is overwritten.
Here is an example script implementing a simple [MainLoop]:
[codeblocks]
[gdscript]
diff --git a/doc/classes/MeshInstance3D.xml b/doc/classes/MeshInstance3D.xml
index d8e2c43566..a0a773b90a 100644
--- a/doc/classes/MeshInstance3D.xml
+++ b/doc/classes/MeshInstance3D.xml
@@ -120,7 +120,7 @@
<param index="1" name="material" type="Material" />
<description>
Sets the override [param material] for the specified [param surface] of the [Mesh] resource. This material is associated with this [MeshInstance3D] rather than with [member mesh].
- [b]Note:[/b] This assigns the [Material] associated to the [MeshInstance3D]'s Surface Material Override properties, not the material within the [Mesh] resource. To set the material within the [Mesh] resource, use [method Mesh.surface_get_material] instead.
+ [b]Note:[/b] This assigns the [Material] associated to the [MeshInstance3D]'s Surface Material Override properties, not the material within the [Mesh] resource. To set the material within the [Mesh] resource, use [method Mesh.surface_set_material] instead.
</description>
</method>
</methods>
diff --git a/doc/classes/MultiplayerAPI.xml b/doc/classes/MultiplayerAPI.xml
index d5016867a7..75cb13d25d 100644
--- a/doc/classes/MultiplayerAPI.xml
+++ b/doc/classes/MultiplayerAPI.xml
@@ -88,7 +88,7 @@
<param index="3" name="arguments" type="Array" default="[]" />
<description>
Sends an RPC to the target [param peer]. The given [param method] will be called on the remote [param object] with the provided [param arguments]. The RPC may also be called locally depending on the implementation and RPC configuration. See [method Node.rpc] and [method Node.rpc_config].
- [b]Note:[/b] Prefer using [method Node.rpc], [method Node.rpc_id], or [code]my_method.rpc(peer, arg1, arg2, ...)[/code] (in GDScript), since they are faster. This method is mostly useful in conjunction with [MultiplayerAPIExtension] when augmenting or replacing the multiplayer capabilities.
+ [b]Note:[/b] Prefer using [method Node.rpc], [method Node.rpc_id], or [code]my_method.rpc(peer, arg1, arg2, ...)[/code] (in GDScript), since they are faster. This method is mostly useful in conjunction with [MultiplayerAPIExtension] when extending or replacing the multiplayer capabilities.
</description>
</method>
<method name="set_default_interface" qualifiers="static">
diff --git a/doc/classes/MultiplayerAPIExtension.xml b/doc/classes/MultiplayerAPIExtension.xml
index cc6d3b7fcf..acb6a2c176 100644
--- a/doc/classes/MultiplayerAPIExtension.xml
+++ b/doc/classes/MultiplayerAPIExtension.xml
@@ -4,14 +4,14 @@
Base class used for extending the [MultiplayerAPI].
</brief_description>
<description>
- This class can be used to augment or replace the default [MultiplayerAPI] implementation via script or extensions.
- The following example augment the default implementation ([SceneMultiplayer]) by logging every RPC being made, and every object being configured for replication.
+ This class can be used to extend or replace the default [MultiplayerAPI] implementation via script or extensions.
+ The following example extend the default implementation ([SceneMultiplayer]) by logging every RPC being made, and every object being configured for replication.
[codeblocks]
[gdscript]
extends MultiplayerAPIExtension
class_name LogMultiplayer
- # We want to augment the default SceneMultiplayer.
+ # We want to extend the default SceneMultiplayer.
var base_multiplayer = SceneMultiplayer.new()
func _init():
@@ -49,7 +49,7 @@
print("Removing node %s from the spawn list. Spawner: %s" % [object, config])
return base_multiplayer.object_configuration_remove(object, config)
- # These can be optional, but in our case we want to augment SceneMultiplayer, so forward everything.
+ # These can be optional, but in our case we want to extend SceneMultiplayer, so forward everything.
func _set_multiplayer_peer(p_peer: MultiplayerPeer):
base_multiplayer.multiplayer_peer = p_peer
@@ -69,7 +69,7 @@
# autoload.gd
func _enter_tree():
# Sets our custom multiplayer as the main one in SceneTree.
- get_tree().set_multiplayer(LogMultiplayer.new())
+ get_tree().set_multiplayer(LogMultiplayer.new())
[/gdscript]
[/codeblocks]
Native extensions can alternatively use the [method MultiplayerAPI.set_default_interface] method during initialization to configure themselves as the default implementation.
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index c07948b546..3cb76e2926 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -1006,8 +1006,8 @@
[b]Note:[/b] When changing the name, the following characters will be replaced with an underscore: ([code].[/code] [code]:[/code] [code]@[/code] [code]/[/code] [code]"[/code] [code]%[/code]). In particular, the [code]@[/code] character is reserved for auto-generated names. See also [method String.validate_node_name].
</member>
<member name="owner" type="Node" setter="set_owner" getter="get_owner">
- The owner of this node. The owner must be an ancestor of this node. When packing the owner node in a [PackedScene], all the nodes it owns are also saved with it.
- [b]Note:[/b] In the editor, nodes not owned by the scene root are usually not displayed in the Scene dock, and will [b]not[/b] be saved. To prevent this, remember to set the owner after calling [method add_child]. See also (see [member unique_name_in_owner])
+ The owner of this node. The owner must be an ancestor of this node. When packing the owner node in a [PackedScene], all the nodes it owns are also saved with it. See also [member unique_name_in_owner].
+ [b]Note:[/b] In the editor, nodes not owned by the scene root are usually not displayed in the Scene dock, and will [b]not[/b] be saved. To prevent this, remember to set the owner after calling [method add_child].
</member>
<member name="physics_interpolation_mode" type="int" setter="set_physics_interpolation_mode" getter="get_physics_interpolation_mode" enum="Node.PhysicsInterpolationMode" default="0">
Allows enabling or disabling physics interpolation per node, offering a finer grain of control than turning physics interpolation on and off globally. See [member ProjectSettings.physics/common/physics_interpolation] and [member SceneTree.physics_interpolation] for the global setting.
diff --git a/doc/classes/NodePath.xml b/doc/classes/NodePath.xml
index d0ec81ab45..628c7106f2 100644
--- a/doc/classes/NodePath.xml
+++ b/doc/classes/NodePath.xml
@@ -57,7 +57,7 @@
<description>
Constructs a [NodePath] from a [String]. The created path is absolute if prefixed with a slash (see [method is_absolute]).
The "subnames" optionally included after the path to the target node can point to properties, and can also be nested.
- Examples of strings that could be node paths:
+ The following strings can be valid node paths:
[codeblock]
# Points to the Sprite2D node.
"Level/RigidBody2D/Sprite2D"
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 777950c075..2389db1301 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -23,7 +23,7 @@
<return type="void" />
<description>
Shuts down the system MIDI driver. Godot will no longer receive [InputEventMIDI]. See also [method open_midi_inputs] and [method get_connected_midi_inputs].
- [b]Note:[/b] This method is implemented on Linux, macOS and Windows.
+ [b]Note:[/b] This method is implemented on Linux, macOS, and Windows.
</description>
</method>
<method name="crash">
@@ -53,7 +53,7 @@
Creates a new process that runs independently of Godot. It will not terminate when Godot terminates. The path specified in [param path] must exist and be an executable file or macOS [code].app[/code] bundle. The path is resolved based on the current platform. The [param arguments] are used in the given order and separated by a space.
On Windows, if [param open_console] is [code]true[/code] and the process is a console app, a new terminal window will be opened.
If the process is successfully created, this method returns its process ID, which you can use to monitor the process (and potentially terminate it with [method kill]). Otherwise, this method returns [code]-1[/code].
- For example, running another instance of the project:
+ [b]Example:[/b] Run another instance of the project:
[codeblocks]
[gdscript]
var pid = OS.create_process(OS.get_executable_path(), [])
@@ -184,7 +184,7 @@
Command-line arguments can be written in any form, including both [code]--key value[/code] and [code]--key=value[/code] forms so they can be properly parsed, as long as custom command-line arguments do not conflict with engine arguments.
You can also incorporate environment variables using the [method get_environment] method.
You can set [member ProjectSettings.editor/run/main_run_args] to define command-line arguments to be passed by the editor when running the project.
- Here's a minimal example on how to parse command-line arguments into a [Dictionary] using the [code]--key=value[/code] form for arguments:
+ [b]Example:[/b] Parse command-line arguments into a [Dictionary] using the [code]--key=value[/code] form for arguments:
[codeblocks]
[gdscript]
var arguments = {}
@@ -244,7 +244,7 @@
<return type="PackedStringArray" />
<description>
Returns an array of connected MIDI device names, if they exist. Returns an empty array if the system MIDI driver has not previously been initialized with [method open_midi_inputs]. See also [method close_midi_inputs].
- [b]Note:[/b] This method is implemented on Linux, macOS and Windows.
+ [b]Note:[/b] This method is implemented on Linux, macOS, and Windows.
</description>
</method>
<method name="get_data_dir" qualifiers="const">
@@ -356,7 +356,7 @@
<return type="String" />
<description>
Returns the model name of the current device.
- [b]Note:[/b] This method is implemented on Android and iOS. Returns [code]"GenericDevice"[/code] on unsupported platforms.
+ [b]Note:[/b] This method is implemented on Android, iOS, macOS, and Windows. Returns [code]"GenericDevice"[/code] on unsupported platforms.
</description>
</method>
<method name="get_name" qualifiers="const">
@@ -466,6 +466,24 @@
Returns the amount of static memory being used by the program in bytes. Only works in debug builds.
</description>
</method>
+ <method name="get_stderr_type" qualifiers="const">
+ <return type="int" enum="OS.StdHandleType" />
+ <description>
+ Returns type of the standard error device.
+ </description>
+ </method>
+ <method name="get_stdin_type" qualifiers="const">
+ <return type="int" enum="OS.StdHandleType" />
+ <description>
+ Returns type of the standard input device.
+ </description>
+ </method>
+ <method name="get_stdout_type" qualifiers="const">
+ <return type="int" enum="OS.StdHandleType" />
+ <description>
+ Returns type of the standard output device.
+ </description>
+ </method>
<method name="get_system_ca_certificates">
<return type="String" />
<description>
@@ -680,15 +698,32 @@
<return type="void" />
<description>
Initializes the singleton for the system MIDI driver, allowing Godot to receive [InputEventMIDI]. See also [method get_connected_midi_inputs] and [method close_midi_inputs].
- [b]Note:[/b] This method is implemented on Linux, macOS and Windows.
+ [b]Note:[/b] This method is implemented on Linux, macOS, and Windows.
+ </description>
+ </method>
+ <method name="read_buffer_from_stdin">
+ <return type="PackedByteArray" />
+ <param index="0" name="buffer_size" type="int" />
+ <description>
+ Reads a user input as raw data from the standard input. This operation can be [i]blocking[/i], which causes the window to freeze if [method read_string_from_stdin] is called on the main thread.
+ - If standard input is console, this method will block until the program receives a line break in standard input (usually by the user pressing [kbd]Enter[/kbd]).
+ - If standard input is pipe, this method will block until a specific amount of data is read or pipe is closed.
+ - If standard input is a file, this method will read a specific amount of data (or less if end-of-file is reached) and return immediately.
+ [b]Note:[/b] This method is implemented on Linux, macOS, and Windows.
+ [b]Note:[/b] On exported Windows builds, run the console wrapper executable to access the terminal. If standard input is console, calling this method without console wrapped will freeze permanently. If standard input is pipe or file, it can be used without console wrapper. If you need a single executable with full console support, use a custom build compiled with the [code]windows_subsystem=console[/code] flag.
</description>
</method>
<method name="read_string_from_stdin">
<return type="String" />
+ <param index="0" name="buffer_size" type="int" />
<description>
- Reads a user input string from the standard input (usually the terminal). This operation is [i]blocking[/i], which causes the window to freeze if [method read_string_from_stdin] is called on the main thread. The thread calling [method read_string_from_stdin] will block until the program receives a line break in standard input (usually by the user pressing [kbd]Enter[/kbd]).
- [b]Note:[/b] This method is implemented on Linux, macOS and Windows.
- [b]Note:[/b] On exported Windows builds, run the console wrapper executable to access the terminal. Otherwise, the standard input will not work correctly. If you need a single executable with console support, use a custom build compiled with the [code]windows_subsystem=console[/code] flag.
+ Reads a user input as a UTF-8 encoded string from the standard input. This operation can be [i]blocking[/i], which causes the window to freeze if [method read_string_from_stdin] is called on the main thread.
+ - If standard input is console, this method will block until the program receives a line break in standard input (usually by the user pressing [kbd]Enter[/kbd]).
+ - If standard input is pipe, this method will block until a specific amount of data is read or pipe is closed.
+ - If standard input is a file, this method will read a specific amount of data (or less if end-of-file is reached) and return immediately.
+ [b]Note:[/b] This method automatically replaces [code]\r\n[/code] line breaks with [code]\n[/code] and removes them from the end of the string. Use [method read_buffer_from_stdin] to read the unprocessed data.
+ [b]Note:[/b] This method is implemented on Linux, macOS, and Windows.
+ [b]Note:[/b] On exported Windows builds, run the console wrapper executable to access the terminal. If standard input is console, calling this method without console wrapped will freeze permanently. If standard input is pipe or file, it can be used without console wrapper. If you need a single executable with full console support, use a custom build compiled with the [code]windows_subsystem=console[/code] flag.
</description>
</method>
<method name="request_permission">
@@ -831,5 +866,20 @@
<constant name="SYSTEM_DIR_RINGTONES" value="7" enum="SystemDir">
Refers to the Ringtones directory path.
</constant>
+ <constant name="STD_HANDLE_INVALID" value="0" enum="StdHandleType">
+ Standard I/O device is invalid. No data can be received from or sent to these standard I/O devices.
+ </constant>
+ <constant name="STD_HANDLE_CONSOLE" value="1" enum="StdHandleType">
+ Standard I/O device is a console. This typically occurs when Godot is run from a terminal with no redirection. This is also used for all standard I/O devices when running Godot from the editor, at least on desktop platforms.
+ </constant>
+ <constant name="STD_HANDLE_FILE" value="2" enum="StdHandleType">
+ Standard I/O device is a regular file. This typically occurs with redirection from a terminal, e.g. [code]godot &gt; stdout.txt[/code], [code]godot &lt; stdin.txt[/code] or [code]godot &gt; stdout_stderr.txt 2&gt;&amp;1[/code].
+ </constant>
+ <constant name="STD_HANDLE_PIPE" value="3" enum="StdHandleType">
+ Standard I/O device is a FIFO/pipe. This typically occurs with pipe usage from a terminal, e.g. [code]echo "Hello" | godot[/code].
+ </constant>
+ <constant name="STD_HANDLE_UNKNOWN" value="4" enum="StdHandleType">
+ Standard I/O device type is unknown.
+ </constant>
</constants>
</class>
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index 9319d92632..73fd7e1943 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -344,7 +344,7 @@
return "Welcome to Godot 4!"
func _init():
- print(self) # Prints Welcome to Godot 4!"
+ print(self) # Prints "Welcome to Godot 4!"
var a = str(self) # a is "Welcome to Godot 4!"
[/codeblock]
</description>
@@ -407,7 +407,7 @@
<param index="0" name="signal" type="String" />
<param index="1" name="arguments" type="Array" default="[]" />
<description>
- Adds a user-defined [param signal]. Optional arguments for the signal can be added as an [Array] of dictionaries, each defining a [code]name[/code] [String] and a [code]type[/code] [int] (see [enum Variant.Type]). See also [method has_user_signal] and [method remove_user_signal].
+ Adds a user-defined signal named [param signal]. Optional arguments for the signal can be added as an [Array] of dictionaries, each defining a [code]name[/code] [String] and a [code]type[/code] [int] (see [enum Variant.Type]). See also [method has_user_signal] and [method remove_user_signal].
[codeblocks]
[gdscript]
add_user_signal("hurt", [
@@ -855,7 +855,7 @@
<param index="0" name="signal" type="StringName" />
<description>
Returns [code]true[/code] if the given [param signal] name exists in the object.
- [b]Note:[/b] In C#, [param signal] must be in snake_case when referring to built-in Godot methods. Prefer using the names exposed in the [code]SignalName[/code] class to avoid allocating a new [StringName] on each call.
+ [b]Note:[/b] In C#, [param signal] must be in snake_case when referring to built-in Godot signals. Prefer using the names exposed in the [code]SignalName[/code] class to avoid allocating a new [StringName] on each call.
</description>
</method>
<method name="has_user_signal" qualifiers="const">
@@ -899,7 +899,7 @@
<param index="1" name="callable" type="Callable" />
<description>
Returns [code]true[/code] if a connection exists between the given [param signal] name and [param callable].
- [b]Note:[/b] In C#, [param signal] must be in snake_case when referring to built-in Godot methods. Prefer using the names exposed in the [code]SignalName[/code] class to avoid allocating a new [StringName] on each call.
+ [b]Note:[/b] In C#, [param signal] must be in snake_case when referring to built-in Godot signals. Prefer using the names exposed in the [code]SignalName[/code] class to avoid allocating a new [StringName] on each call.
</description>
</method>
<method name="is_queued_for_deletion" qualifiers="const">
diff --git a/doc/classes/PackedInt64Array.xml b/doc/classes/PackedInt64Array.xml
index cfaf012a55..b82d0de350 100644
--- a/doc/classes/PackedInt64Array.xml
+++ b/doc/classes/PackedInt64Array.xml
@@ -6,7 +6,7 @@
<description>
An array specifically designed to hold 64-bit integer values. Packs data tightly, so it saves memory for large array sizes.
[b]Note:[/b] This type stores signed 64-bit integers, which means it can take values in the interval [code][-2^63, 2^63 - 1][/code], i.e. [code][-9223372036854775808, 9223372036854775807][/code]. Exceeding those bounds will wrap around. If you only need to pack 32-bit integers tightly, see [PackedInt32Array] for a more memory-friendly alternative.
- [b]Differences between packed arrays, typed arrays, and untyped arrays:[/b] Packed arrays are generally faster to iterate on and modify compared to a typed array of the same type (e.g. [PackedInt32Array] versus [code]Array[int][/code]). Also, packed arrays consume less memory. As a downside, packed arrays are less flexible as they don't offer as many convenience methods such as [method Array.map]. Typed arrays are in turn faster to iterate on and modify than untyped arrays.
+ [b]Differences between packed arrays, typed arrays, and untyped arrays:[/b] Packed arrays are generally faster to iterate on and modify compared to a typed array of the same type (e.g. [PackedInt64Array] versus [code]Array[int][/code]). Also, packed arrays consume less memory. As a downside, packed arrays are less flexible as they don't offer as many convenience methods such as [method Array.map]. Typed arrays are in turn faster to iterate on and modify than untyped arrays.
[b]Note:[/b] Packed arrays are always passed by reference. To get a copy of an array that can be modified independently of the original array, use [method duplicate]. This is [i]not[/i] the case for built-in properties and methods. The returned packed array of these are a copies, and changing it will [i]not[/i] affect the original value. To update a built-in property you need to modify the returned array, and then assign it to the property again.
</description>
<tutorials>
diff --git a/doc/classes/PackedScene.xml b/doc/classes/PackedScene.xml
index 415e468e21..baff5fed57 100644
--- a/doc/classes/PackedScene.xml
+++ b/doc/classes/PackedScene.xml
@@ -7,7 +7,7 @@
A simplified interface to a scene file. Provides access to operations and checks that can be performed on the scene resource itself.
Can be used to save a node to a file. When saving, the node as well as all the nodes it owns get saved (see [member Node.owner] property).
[b]Note:[/b] The node doesn't need to own itself.
- [b]Example of loading a saved scene:[/b]
+ [b]Example:[/b] Load a saved scene:
[codeblocks]
[gdscript]
# Use load() instead of preload() if the path isn't known at compile-time.
@@ -22,7 +22,7 @@
AddChild(scene);
[/csharp]
[/codeblocks]
- [b]Example of saving a node with different owners:[/b] The following example creates 3 objects: [Node2D] ([code]node[/code]), [RigidBody2D] ([code]body[/code]) and [CollisionObject2D] ([code]collision[/code]). [code]collision[/code] is a child of [code]body[/code] which is a child of [code]node[/code]. Only [code]body[/code] is owned by [code]node[/code] and [method pack] will therefore only save those two nodes, but not [code]collision[/code].
+ [b]Example:[/b] Save a node with different owners. The following example creates 3 objects: [Node2D] ([code]node[/code]), [RigidBody2D] ([code]body[/code]) and [CollisionObject2D] ([code]collision[/code]). [code]collision[/code] is a child of [code]body[/code] which is a child of [code]node[/code]. Only [code]body[/code] is owned by [code]node[/code] and [method pack] will therefore only save those two nodes, but not [code]collision[/code].
[codeblocks]
[gdscript]
# Create the objects.
diff --git a/doc/classes/PackedVector4Array.xml b/doc/classes/PackedVector4Array.xml
index 6dbfc7413d..7bebee79c7 100644
--- a/doc/classes/PackedVector4Array.xml
+++ b/doc/classes/PackedVector4Array.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
An array specifically designed to hold [Vector4]. Packs data tightly, so it saves memory for large array sizes.
+ [b]Differences between packed arrays, typed arrays, and untyped arrays:[/b] Packed arrays are generally faster to iterate on and modify compared to a typed array of the same type (e.g. [PackedVector4Array] versus [code]Array[Vector4][/code]). Also, packed arrays consume less memory. As a downside, packed arrays are less flexible as they don't offer as many convenience methods such as [method Array.map]. Typed arrays are in turn faster to iterate on and modify than untyped arrays.
[b]Note:[/b] Packed arrays are always passed by reference. To get a copy of an array that can be modified independently of the original array, use [method duplicate]. This is [i]not[/i] the case for built-in properties and methods. The returned packed array of these are a copies, and changing it will [i]not[/i] affect the original value. To update a built-in property you need to modify the returned array, and then assign it to the property again.
</description>
<tutorials>
diff --git a/doc/classes/PacketPeerUDP.xml b/doc/classes/PacketPeerUDP.xml
index 12d3178797..05b6e646c0 100644
--- a/doc/classes/PacketPeerUDP.xml
+++ b/doc/classes/PacketPeerUDP.xml
@@ -4,7 +4,32 @@
UDP packet peer.
</brief_description>
<description>
- UDP packet peer. Can be used to send raw UDP packets as well as [Variant]s.
+ UDP packet peer. Can be used to send and receive raw UDP packets as well as [Variant]s.
+ [b]Example:[/b] Send a packet:
+ [codeblock]
+ var peer = PacketPeerUDP.new()
+
+ # Optionally, you can select the local port used to send the packet.
+ peer.bind(4444)
+
+ peer.set_dest_address("1.1.1.1", 4433)
+ peer.put_packet("hello".to_utf8_buffer())
+ [/codeblock]
+ [b]Example:[/b] Listen for packets:
+ [codeblock]
+ var peer
+
+ func _ready():
+ peer = PacketPeerUDP.new()
+ peer.bind(4433)
+
+
+ func _process(_delta):
+ if peer.get_available_packet_count() &gt; 0:
+ var array_bytes = peer.get_packet()
+ var packet_string = array_bytes.get_string_from_ascii()
+ print("Received message: ", packet_string)
+ [/codeblock]
[b]Note:[/b] When exporting to Android, make sure to enable the [code]INTERNET[/code] permission in the Android export preset before exporting the project or using one-click deploy. Otherwise, network communication of any kind will be blocked by Android.
</description>
<tutorials>
diff --git a/doc/classes/PhysicalBone3D.xml b/doc/classes/PhysicalBone3D.xml
index d58ea9487e..e2ad3db0a5 100644
--- a/doc/classes/PhysicalBone3D.xml
+++ b/doc/classes/PhysicalBone3D.xml
@@ -57,7 +57,7 @@
</methods>
<members>
<member name="angular_damp" type="float" setter="set_angular_damp" getter="get_angular_damp" default="0.0">
- Damps the body's rotation. By default, the body will use the [b]Default Angular Damp[/b] in [b]Project &gt; Project Settings &gt; Physics &gt; 3d[/b] or any value override set by an [Area3D] the body is in. Depending on [member angular_damp_mode], you can set [member angular_damp] to be added to or to replace the body's damping value.
+ Damps the body's rotation. By default, the body will use the [member ProjectSettings.physics/3d/default_angular_damp] project setting or any value override set by an [Area3D] the body is in. Depending on [member angular_damp_mode], you can set [member angular_damp] to be added to or to replace the body's damping value.
See [member ProjectSettings.physics/3d/default_angular_damp] for more details about damping.
</member>
<member name="angular_damp_mode" type="int" setter="set_angular_damp_mode" getter="get_angular_damp_mode" enum="PhysicalBone3D.DampMode" default="0">
@@ -84,7 +84,7 @@
The body's friction, from [code]0[/code] (frictionless) to [code]1[/code] (max friction).
</member>
<member name="gravity_scale" type="float" setter="set_gravity_scale" getter="get_gravity_scale" default="1.0">
- This is multiplied by the global 3D gravity setting found in [b]Project &gt; Project Settings &gt; Physics &gt; 3d[/b] to produce the body's gravity. For example, a value of 1 will be normal gravity, 2 will apply double gravity, and 0.5 will apply half gravity to this object.
+ This is multiplied by [member ProjectSettings.physics/3d/default_gravity] to produce this body's gravity. For example, a value of [code]1.0[/code] will apply normal gravity, [code]2.0[/code] will apply double the gravity, and [code]0.5[/code] will apply half the gravity to this body.
</member>
<member name="joint_offset" type="Transform3D" setter="set_joint_offset" getter="get_joint_offset" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)">
Sets the joint's transform.
@@ -96,7 +96,7 @@
Sets the joint type. See [enum JointType] for possible values.
</member>
<member name="linear_damp" type="float" setter="set_linear_damp" getter="get_linear_damp" default="0.0">
- Damps the body's movement. By default, the body will use the [b]Default Linear Damp[/b] in [b]Project &gt; Project Settings &gt; Physics &gt; 3d[/b] or any value override set by an [Area3D] the body is in. Depending on [member linear_damp_mode], you can set [member linear_damp] to be added to or to replace the body's damping value.
+ Damps the body's movement. By default, the body will use [member ProjectSettings.physics/3d/default_linear_damp] or any value override set by an [Area3D] the body is in. Depending on [member linear_damp_mode], [member linear_damp] may be added to or replace the body's damping value.
See [member ProjectSettings.physics/3d/default_linear_damp] for more details about damping.
</member>
<member name="linear_damp_mode" type="int" setter="set_linear_damp_mode" getter="get_linear_damp_mode" enum="PhysicalBone3D.DampMode" default="0">
diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml
index d73cda7460..9fd47cf7f5 100644
--- a/doc/classes/PopupMenu.xml
+++ b/doc/classes/PopupMenu.xml
@@ -135,8 +135,6 @@
Adds a new multistate item with text [param label].
Contrarily to normal binary items, multistate items can have more than two states, as defined by [param max_states]. The default value is defined by [param default_state].
An [param id] can optionally be provided, as well as an accelerator ([param accel]). If no [param id] is provided, one will be created from the index. If no [param accel] is provided, then the default value of 0 (corresponding to [constant @GlobalScope.KEY_NONE]) will be assigned to the item (which means it won't have any accelerator). See [method get_item_accelerator] for more info on accelerators.
- [b]Note:[/b] Multistate items don't update their state automatically and must be done manually. See [method toggle_item_multistate], [method set_item_multistate] and [method get_item_multistate] for more info on how to control it.
- Example usage:
[codeblock]
func _ready():
add_multistate_item("Item", 3, 0)
@@ -152,6 +150,7 @@
print("Third state")
)
[/codeblock]
+ [b]Note:[/b] Multistate items don't update their state automatically and must be done manually. See [method toggle_item_multistate], [method set_item_multistate] and [method get_item_multistate] for more info on how to control it.
</description>
</method>
<method name="add_radio_check_item">
diff --git a/doc/classes/PrimitiveMesh.xml b/doc/classes/PrimitiveMesh.xml
index 58a8da12da..ba48d2dcf5 100644
--- a/doc/classes/PrimitiveMesh.xml
+++ b/doc/classes/PrimitiveMesh.xml
@@ -18,7 +18,8 @@
<method name="get_mesh_arrays" qualifiers="const">
<return type="Array" />
<description>
- Returns mesh arrays used to constitute surface of [Mesh]. The result can be passed to [method ArrayMesh.add_surface_from_arrays] to create a new surface. For example:
+ Returns the mesh arrays used to make up the surface of this primitive mesh.
+ [b]Example:[/b] Pass the result to [method ArrayMesh.add_surface_from_arrays] to create a new surface:
[codeblocks]
[gdscript]
var c = CylinderMesh.new()
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index f5a5045ad5..91961fcf02 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -103,7 +103,7 @@
<param index="0" name="name" type="StringName" />
<description>
Similar to [method get_setting], but applies feature tag overrides if any exists and is valid.
- [b]Example:[/b] If the setting override [code]"application/config/name.windows"[/code] exists, and the following code is executed on a [i]Windows[/i] operating system, the overridden setting is printed instead:
+ [b]Example:[/b] If the setting override [code]"application/config/name.windows"[/code] exists, and the following code is executed on a [i]Windows[/i] operating system, the overridden setting is printed instead:
[codeblocks]
[gdscript]
print(ProjectSettings.get_setting_with_override("application/config/name"))
@@ -2474,10 +2474,10 @@
Number of blur passes to use when computing screen-space ambient occlusion. A higher number will result in a smoother look, but will be slower to compute and will have less high-frequency detail.
</member>
<member name="rendering/environment/ssao/fadeout_from" type="float" setter="" getter="" default="50.0">
- Distance at which the screen-space ambient occlusion effect starts to fade out. Use this hide ambient occlusion at great distances.
+ Distance at which the screen-space ambient occlusion effect starts to fade out. Use this hide ambient occlusion from far away.
</member>
<member name="rendering/environment/ssao/fadeout_to" type="float" setter="" getter="" default="300.0">
- Distance at which the screen-space ambient occlusion is fully faded out. Use this hide ambient occlusion at great distances.
+ Distance at which the screen-space ambient occlusion is fully faded out. Use this hide ambient occlusion from far away.
</member>
<member name="rendering/environment/ssao/half_size" type="bool" setter="" getter="" default="true">
If [code]true[/code], screen-space ambient occlusion will be rendered at half size and then upscaled before being added to the scene. This is significantly faster but may miss small details. If [code]false[/code], screen-space ambient occlusion will be rendered at full size.
@@ -2492,10 +2492,10 @@
Number of blur passes to use when computing screen-space indirect lighting. A higher number will result in a smoother look, but will be slower to compute and will have less high-frequency detail.
</member>
<member name="rendering/environment/ssil/fadeout_from" type="float" setter="" getter="" default="50.0">
- Distance at which the screen-space indirect lighting effect starts to fade out. Use this hide screen-space indirect lighting at great distances.
+ Distance at which the screen-space indirect lighting effect starts to fade out. Use this to hide screen-space indirect lighting from far away.
</member>
<member name="rendering/environment/ssil/fadeout_to" type="float" setter="" getter="" default="300.0">
- Distance at which the screen-space indirect lighting is fully faded out. Use this hide screen-space indirect lighting at great distances.
+ Distance at which the screen-space indirect lighting is fully faded out. Use this to hide screen-space indirect lighting from far away.
</member>
<member name="rendering/environment/ssil/half_size" type="bool" setter="" getter="" default="true">
If [code]true[/code], screen-space indirect lighting will be rendered at half size and then upscaled before being added to the scene. This is significantly faster but may miss small details and may result in some objects appearing to glow at their edges.
diff --git a/doc/classes/Projection.xml b/doc/classes/Projection.xml
index f781083abf..091e0bf54f 100644
--- a/doc/classes/Projection.xml
+++ b/doc/classes/Projection.xml
@@ -278,22 +278,22 @@
</member>
</members>
<constants>
- <constant name="PLANE_NEAR" value="0">
+ <constant name="PLANE_NEAR" value="0" enum="Planes">
The index value of the projection's near clipping plane.
</constant>
- <constant name="PLANE_FAR" value="1">
+ <constant name="PLANE_FAR" value="1" enum="Planes">
The index value of the projection's far clipping plane.
</constant>
- <constant name="PLANE_LEFT" value="2">
+ <constant name="PLANE_LEFT" value="2" enum="Planes">
The index value of the projection's left clipping plane.
</constant>
- <constant name="PLANE_TOP" value="3">
+ <constant name="PLANE_TOP" value="3" enum="Planes">
The index value of the projection's top clipping plane.
</constant>
- <constant name="PLANE_RIGHT" value="4">
+ <constant name="PLANE_RIGHT" value="4" enum="Planes">
The index value of the projection's right clipping plane.
</constant>
- <constant name="PLANE_BOTTOM" value="5">
+ <constant name="PLANE_BOTTOM" value="5" enum="Planes">
The index value of the projection bottom clipping plane.
</constant>
<constant name="IDENTITY" value="Projection(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)">
diff --git a/doc/classes/RDTextureFormat.xml b/doc/classes/RDTextureFormat.xml
index f8de7feda0..ac875ab7c1 100644
--- a/doc/classes/RDTextureFormat.xml
+++ b/doc/classes/RDTextureFormat.xml
@@ -13,12 +13,14 @@
<return type="void" />
<param index="0" name="format" type="int" enum="RenderingDevice.DataFormat" />
<description>
+ Adds [param format] as a valid format for the corresponding [RDTextureView]'s [member RDTextureView.format_override] property. If any format is added as shareable, then the main [member format] must also be added.
</description>
</method>
<method name="remove_shareable_format">
<return type="void" />
<param index="0" name="format" type="int" enum="RenderingDevice.DataFormat" />
<description>
+ Removes [param format] from the list of valid formats that the corresponding [RDTextureView]'s [member RDTextureView.format_override] property can be set to.
</description>
</method>
</methods>
diff --git a/doc/classes/RDTextureView.xml b/doc/classes/RDTextureView.xml
index 30b6bfedf5..bd8102d553 100644
--- a/doc/classes/RDTextureView.xml
+++ b/doc/classes/RDTextureView.xml
@@ -10,7 +10,7 @@
</tutorials>
<members>
<member name="format_override" type="int" setter="set_format_override" getter="get_format_override" enum="RenderingDevice.DataFormat" default="218">
- Optional override for the data format to return sampled values in. The default value of [constant RenderingDevice.DATA_FORMAT_MAX] does not override the format.
+ Optional override for the data format to return sampled values in. The corresponding [RDTextureFormat] must have had this added as a shareable format. The default value of [constant RenderingDevice.DATA_FORMAT_MAX] does not override the format.
</member>
<member name="swizzle_a" type="int" setter="set_swizzle_a" getter="get_swizzle_a" enum="RenderingDevice.TextureSwizzle" default="6">
The channel to sample when sampling the alpha channel.
diff --git a/doc/classes/Range.xml b/doc/classes/Range.xml
index 820ff04b70..a76676489f 100644
--- a/doc/classes/Range.xml
+++ b/doc/classes/Range.xml
@@ -54,7 +54,7 @@
Minimum value. Range is clamped if [member value] is less than [member min_value].
</member>
<member name="page" type="float" setter="set_page" getter="get_page" default="0.0">
- Page size. Used mainly for [ScrollBar]. ScrollBar's length is its size multiplied by [member page] over the difference between [member min_value] and [member max_value].
+ Page size. Used mainly for [ScrollBar]. A [ScrollBar]'s grabber length is the [ScrollBar]'s size multiplied by [member page] over the difference between [member min_value] and [member max_value].
</member>
<member name="ratio" type="float" setter="set_as_ratio" getter="get_as_ratio">
The value mapped between 0 and 1.
diff --git a/doc/classes/RenderData.xml b/doc/classes/RenderData.xml
index 065505e6c6..c2a598c43f 100644
--- a/doc/classes/RenderData.xml
+++ b/doc/classes/RenderData.xml
@@ -19,7 +19,7 @@
<method name="get_environment" qualifiers="const">
<return type="RID" />
<description>
- Returns the [RID] of the environments object in the [RenderingServer] being used to render this viewport.
+ Returns the [RID] of the environment object in the [RenderingServer] being used to render this viewport.
</description>
</method>
<method name="get_render_scene_buffers" qualifiers="const">
diff --git a/doc/classes/RenderSceneBuffersRD.xml b/doc/classes/RenderSceneBuffersRD.xml
index 7b5aac5b61..6a5aba1dbc 100644
--- a/doc/classes/RenderSceneBuffersRD.xml
+++ b/doc/classes/RenderSceneBuffersRD.xml
@@ -52,7 +52,7 @@
<param index="2" name="view_name" type="StringName" />
<param index="3" name="view" type="RDTextureView" />
<description>
- Create a new texture view for an existing texture and cache this under the given view_name. Will return the existing teture view if it already exists. Will error if the source texture doesn't exist.
+ Create a new texture view for an existing texture and cache this under the given [param view_name]. Will return the existing texture view if it already exists. Will error if the source texture doesn't exist.
</description>
</method>
<method name="get_color_layer">
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 76949fb84e..6be53b336b 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -1614,7 +1614,7 @@
<return type="RID" />
<description>
Returns the RID of a 256×256 texture with a testing pattern on it (in [constant Image.FORMAT_RGB8] format). This texture will be created and returned on the first call to [method get_test_texture], then it will be cached for subsequent calls. See also [method get_white_texture].
- Example of getting the test texture and applying it to a [Sprite2D] node:
+ [b]Example:[/b] Get the test texture and apply it to a [Sprite2D] node:
[codeblock]
var texture_rid = RenderingServer.get_test_texture()
var texture = ImageTexture.create_from_image(RenderingServer.texture_2d_get(texture_rid))
@@ -1655,7 +1655,7 @@
<return type="RID" />
<description>
Returns the ID of a 4×4 white texture (in [constant Image.FORMAT_RGB8] format). This texture will be created and returned on the first call to [method get_white_texture], then it will be cached for subsequent calls. See also [method get_test_texture].
- Example of getting the white texture and applying it to a [Sprite2D] node:
+ [b]Example:[/b] Get the white texture and apply it to a [Sprite2D] node:
[codeblock]
var texture_rid = RenderingServer.get_white_texture()
var texture = ImageTexture.create_from_image(RenderingServer.texture_2d_get(texture_rid))
@@ -2545,6 +2545,13 @@
[b]Note:[/b] If the buffer is in the engine's internal cache, it will have to be fetched from GPU memory and possibly decompressed. This means [method multimesh_get_buffer] is potentially a slow operation and should be avoided whenever possible.
</description>
</method>
+ <method name="multimesh_get_buffer_rd_rid" qualifiers="const">
+ <return type="RID" />
+ <param index="0" name="multimesh" type="RID" />
+ <description>
+ Returns the [RenderingDevice] [RID] handle of the [MultiMesh], which can be used as any other buffer on the Rendering Device.
+ </description>
+ </method>
<method name="multimesh_get_custom_aabb" qualifiers="const">
<return type="AABB" />
<param index="0" name="multimesh" type="RID" />
@@ -3314,7 +3321,8 @@
<return type="void" />
<param index="0" name="generate" type="bool" />
<description>
- This method is currently unimplemented and does nothing if called with [param generate] set to [code]true[/code].
+ If [param generate] is [code]true[/code], generates debug wireframes for all meshes that are loaded when using the Compatibility renderer. By default, the engine does not generate debug wireframes at runtime, since they slow down loading of assets and take up VRAM.
+ [b]Note:[/b] You must call this method before loading any meshes when using the Compatibility renderer, otherwise wireframes will not be used.
</description>
</method>
<method name="set_default_clear_color">
@@ -3528,7 +3536,7 @@
<param index="0" name="texture" type="RID" />
<description>
Returns an [Image] instance from the given [param texture] [RID].
- Example of getting the test texture from [method get_test_texture] and applying it to a [Sprite2D] node:
+ [b]Example:[/b] Get the test texture from [method get_test_texture] and apply it to a [Sprite2D] node:
[codeblock]
var texture_rid = RenderingServer.get_test_texture()
var texture = ImageTexture.create_from_image(RenderingServer.texture_2d_get(texture_rid))
@@ -5047,6 +5055,7 @@
</constant>
<constant name="VIEWPORT_DEBUG_DRAW_WIREFRAME" value="4" enum="ViewportDebugDraw">
Debug draw draws objects in wireframe.
+ [b]Note:[/b] [method set_debug_generate_wireframes] must be called before loading any meshes for wireframes to be visible when using the Compatibility renderer.
</constant>
<constant name="VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER" value="5" enum="ViewportDebugDraw">
Normal buffer is drawn instead of regular scene so you can see the per-pixel normals that will be used by post-processing effects.
diff --git a/doc/classes/Resource.xml b/doc/classes/Resource.xml
index 18d4047339..0f3a231cb7 100644
--- a/doc/classes/Resource.xml
+++ b/doc/classes/Resource.xml
@@ -37,7 +37,7 @@
<return type="void" />
<description>
Override this method to customize the newly duplicated resource created from [method PackedScene.instantiate], if the original's [member resource_local_to_scene] is set to [code]true[/code].
- [b]Example:[/b] Set a random [code]damage[/code] value to every local resource from an instantiated scene.
+ [b]Example:[/b] Set a random [code]damage[/code] value to every local resource from an instantiated scene:
[codeblock]
extends Resource
diff --git a/doc/classes/ResourceImporterTexture.xml b/doc/classes/ResourceImporterTexture.xml
index 0761702aa1..a39e48c7bf 100644
--- a/doc/classes/ResourceImporterTexture.xml
+++ b/doc/classes/ResourceImporterTexture.xml
@@ -90,9 +90,13 @@
<member name="process/size_limit" type="int" setter="" getter="" default="0">
If set to a value greater than [code]0[/code], the size of the texture is limited on import to a value smaller than or equal to the value specified here. For non-square textures, the size limit affects the longer dimension, with the shorter dimension scaled to preserve aspect ratio. Resizing is performed using cubic interpolation.
This can be used to reduce memory usage without affecting the source images, or avoid issues with textures not displaying on mobile/web platforms (as these usually can't display textures larger than 4096×4096).
+ [b]Note:[/b] Even if this is set to [code]0[/code], import size is limited to the following dimensions for technical reasons. Depending on [member compress/mode], textures will be downsampled on import if necessary:
+ - [b]Lossy:[/b] 16383 pixels width or height, whichever is larger;
+ - [b]Basis Universal:[/b] 16384 pixels width or height, whichever is larger;
+ - [b]All other modes:[/b] 32768 pixels width or height, whichever is larger.
</member>
<member name="roughness/mode" type="int" setter="" getter="" default="0">
- The color channel to consider as a roughness map in this texture. Only effective if Roughness &gt; Src Normal is not empty.
+ The color channel to consider as a roughness map in this texture. Only effective if [member roughness/src_normal] is not empty.
</member>
<member name="roughness/src_normal" type="String" setter="" getter="" default="&quot;&quot;">
The path to the texture to consider as a normal map for roughness filtering on import. Specifying this can help decrease specular aliasing slightly in 3D.
diff --git a/doc/classes/RetargetModifier3D.xml b/doc/classes/RetargetModifier3D.xml
new file mode 100644
index 0000000000..522b954aba
--- /dev/null
+++ b/doc/classes/RetargetModifier3D.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="RetargetModifier3D" inherits="SkeletonModifier3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ A modifier to transfer parent skeleton poses (or global poses) to child skeletons in model space with different rests.
+ </brief_description>
+ <description>
+ Retrieves the pose (or global pose) relative to the parent Skeleton's rest in model space and transfers it to the child Skeleton.
+ This modifier rewrites the pose of the child skeleton directly in the parent skeleton's update process. This means that it overwrites the mapped bone pose set in the normal process on the target skeleton. If you want to set the target skeleton bone pose after retargeting, you will need to add a [SkeletonModifier3D] child to the target skeleton and thereby modify the pose.
+ [b]Note:[/b] When the [member use_global_pose] is enabled, even if it is an unmapped bone, it can cause visual problems because the global pose is applied ignoring the parent bone's pose [b]if it has mapped bone children[/b]. See also [member use_global_pose].
+ </description>
+ <tutorials>
+ </tutorials>
+ <members>
+ <member name="position_enabled" type="bool" setter="set_position_enabled" getter="is_position_enabled" default="true">
+ If [code]true[/code], allows to retarget the position.
+ </member>
+ <member name="profile" type="SkeletonProfile" setter="set_profile" getter="get_profile">
+ [SkeletonProfile] for retargeting bones with names matching the bone list.
+ </member>
+ <member name="rotation_enabled" type="bool" setter="set_rotation_enabled" getter="is_rotation_enabled" default="true">
+ If [code]true[/code], allows to retarget the rotation.
+ </member>
+ <member name="scale_enabled" type="bool" setter="set_scale_enabled" getter="is_scale_enabled" default="true">
+ If [code]true[/code], allows to retarget the scale.
+ </member>
+ <member name="use_global_pose" type="bool" setter="set_use_global_pose" getter="is_using_global_pose" default="false">
+ If [code]false[/code], in case the target skeleton has fewer bones than the source skeleton, the source bone parent's transform will be ignored.
+ Instead, it is possible to retarget between models with different body shapes, and position, rotation, and scale can be retargeted separately.
+ If [code]true[/code], retargeting is performed taking into account global pose.
+ In case the target skeleton has fewer bones than the source skeleton, the source bone parent's transform is taken into account. However, bone length between skeletons must match exactly, if not, the bones will be forced to expand or shrink.
+ This is useful for using dummy bone with length [code]0[/code] to match postures when retargeting between models with different number of bones.
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml
index 2ac346b5c2..8472e57840 100644
--- a/doc/classes/RichTextLabel.xml
+++ b/doc/classes/RichTextLabel.xml
@@ -225,8 +225,8 @@
<return type="void" />
<param index="0" name="effect" type="Variant" />
<description>
- Installs a custom effect. This can also be done in the RichTextLabel inspector using the [member custom_effects] property. [param effect] should be a valid [RichTextEffect].
- Example RichTextEffect:
+ Installs a custom effect. This can also be done in the Inspector through the [member custom_effects] property. [param effect] should be a valid [RichTextEffect].
+ [b]Example:[/b] With the following script extending from [RichTextEffect]:
[codeblock]
# effect.gd
class_name MyCustomEffect
@@ -236,7 +236,7 @@
# ...
[/codeblock]
- Registering the above effect in RichTextLabel from script:
+ The above effect can be installed in [RichTextLabel] from a script:
[codeblock]
# rich_text_label.gd
extends RichTextLabel
diff --git a/doc/classes/RigidBody2D.xml b/doc/classes/RigidBody2D.xml
index 5661d1a276..1977b238e4 100644
--- a/doc/classes/RigidBody2D.xml
+++ b/doc/classes/RigidBody2D.xml
@@ -123,7 +123,7 @@
</methods>
<members>
<member name="angular_damp" type="float" setter="set_angular_damp" getter="get_angular_damp" default="0.0">
- Damps the body's rotation. By default, the body will use the [b]Default Angular Damp[/b] in [b]Project &gt; Project Settings &gt; Physics &gt; 2d[/b] or any value override set by an [Area2D] the body is in. Depending on [member angular_damp_mode], you can set [member angular_damp] to be added to or to replace the body's damping value.
+ Damps the body's rotation. By default, the body will use the [member ProjectSettings.physics/2d/default_angular_damp] setting or any value override set by an [Area2D] the body is in. Depending on [member angular_damp_mode], you can set [member angular_damp] to be added to or to replace the body's damping value.
See [member ProjectSettings.physics/2d/default_angular_damp] for more details about damping.
</member>
<member name="angular_damp_mode" type="int" setter="set_angular_damp_mode" getter="get_angular_damp_mode" enum="RigidBody2D.DampMode" default="0">
@@ -172,7 +172,7 @@
For a body that is always frozen, use [StaticBody2D] or [AnimatableBody2D] instead.
</member>
<member name="gravity_scale" type="float" setter="set_gravity_scale" getter="get_gravity_scale" default="1.0">
- Multiplies the gravity applied to the body. The body's gravity is calculated from the [b]Default Gravity[/b] value in [b]Project &gt; Project Settings &gt; Physics &gt; 2d[/b] and/or any additional gravity vector applied by [Area2D]s.
+ Multiplies the gravity applied to the body. The body's gravity is calculated from the [member ProjectSettings.physics/2d/default_gravity] project setting and/or any additional gravity vector applied by [Area2D]s.
</member>
<member name="inertia" type="float" setter="set_inertia" getter="get_inertia" default="0.0">
The body's moment of inertia. This is like mass, but for rotation: it determines how much torque it takes to rotate the body. The moment of inertia is usually computed automatically from the mass and the shapes, but this property allows you to set a custom value.
@@ -201,7 +201,7 @@
[/codeblocks]
</member>
<member name="linear_damp" type="float" setter="set_linear_damp" getter="get_linear_damp" default="0.0">
- Damps the body's movement. By default, the body will use the [b]Default Linear Damp[/b] in [b]Project &gt; Project Settings &gt; Physics &gt; 2d[/b] or any value override set by an [Area2D] the body is in. Depending on [member linear_damp_mode], you can set [member linear_damp] to be added to or to replace the body's damping value.
+ Damps the body's movement. By default, the body will use the [member ProjectSettings.physics/2d/default_linear_damp] setting or any value override set by an [Area2D] the body is in. Depending on [member linear_damp_mode], you can set [member linear_damp] to be added to or to replace the body's damping value.
See [member ProjectSettings.physics/2d/default_linear_damp] for more details about damping.
</member>
<member name="linear_damp_mode" type="int" setter="set_linear_damp_mode" getter="get_linear_damp_mode" enum="RigidBody2D.DampMode" default="0">
diff --git a/doc/classes/RigidBody3D.xml b/doc/classes/RigidBody3D.xml
index dae904e2a3..de6d5cde3d 100644
--- a/doc/classes/RigidBody3D.xml
+++ b/doc/classes/RigidBody3D.xml
@@ -130,7 +130,7 @@
</methods>
<members>
<member name="angular_damp" type="float" setter="set_angular_damp" getter="get_angular_damp" default="0.0">
- Damps the body's rotation. By default, the body will use the [b]Default Angular Damp[/b] in [b]Project &gt; Project Settings &gt; Physics &gt; 3d[/b] or any value override set by an [Area3D] the body is in. Depending on [member angular_damp_mode], you can set [member angular_damp] to be added to or to replace the body's damping value.
+ Damps the body's rotation. By default, the body will use the [member ProjectSettings.physics/3d/default_angular_damp] project setting or any value override set by an [Area3D] the body is in. Depending on [member angular_damp_mode], you can set [member angular_damp] to be added to or to replace the body's damping value.
See [member ProjectSettings.physics/3d/default_angular_damp] for more details about damping.
</member>
<member name="angular_damp_mode" type="int" setter="set_angular_damp_mode" getter="get_angular_damp_mode" enum="RigidBody3D.DampMode" default="0">
@@ -179,7 +179,7 @@
For a body that is always frozen, use [StaticBody3D] or [AnimatableBody3D] instead.
</member>
<member name="gravity_scale" type="float" setter="set_gravity_scale" getter="get_gravity_scale" default="1.0">
- This is multiplied by the global 3D gravity setting found in [b]Project &gt; Project Settings &gt; Physics &gt; 3d[/b] to produce RigidBody3D's gravity. For example, a value of 1 will be normal gravity, 2 will apply double gravity, and 0.5 will apply half gravity to this object.
+ This is multiplied by [member ProjectSettings.physics/3d/default_gravity] to produce this body's gravity. For example, a value of [code]1.0[/code] will apply normal gravity, [code]2.0[/code] will apply double the gravity, and [code]0.5[/code] will apply half the gravity to this body.
</member>
<member name="inertia" type="Vector3" setter="set_inertia" getter="get_inertia" default="Vector3(0, 0, 0)">
The body's moment of inertia. This is like mass, but for rotation: it determines how much torque it takes to rotate the body on each axis. The moment of inertia is usually computed automatically from the mass and the shapes, but this property allows you to set a custom value.
@@ -208,7 +208,7 @@
[/codeblocks]
</member>
<member name="linear_damp" type="float" setter="set_linear_damp" getter="get_linear_damp" default="0.0">
- Damps the body's movement. By default, the body will use the [b]Default Linear Damp[/b] in [b]Project &gt; Project Settings &gt; Physics &gt; 3d[/b] or any value override set by an [Area3D] the body is in. Depending on [member linear_damp_mode], you can set [member linear_damp] to be added to or to replace the body's damping value.
+ Damps the body's movement. By default, the body will use the [member ProjectSettings.physics/3d/default_linear_damp] project setting or any value override set by an [Area3D] the body is in. Depending on [member linear_damp_mode], you can set [member linear_damp] to be added to or to replace the body's damping value.
See [member ProjectSettings.physics/3d/default_linear_damp] for more details about damping.
</member>
<member name="linear_damp_mode" type="int" setter="set_linear_damp_mode" getter="get_linear_damp_mode" enum="RigidBody3D.DampMode" default="0">
diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml
index f5b808be8e..aa751de5f2 100644
--- a/doc/classes/Skeleton3D.xml
+++ b/doc/classes/Skeleton3D.xml
@@ -393,6 +393,11 @@
[b]Note:[/b] During the update process, this signal is not fired, so modification by [SkeletonModifier3D] is not detected.
</description>
</signal>
+ <signal name="rest_updated">
+ <description>
+ Emitted when the rest is updated.
+ </description>
+ </signal>
<signal name="show_rest_only_changed">
<description>
Emitted when the value of [member show_rest_only] changes.
diff --git a/doc/classes/SkeletonModification2DTwoBoneIK.xml b/doc/classes/SkeletonModification2DTwoBoneIK.xml
index 1c7bb32f4a..d2417ba7bf 100644
--- a/doc/classes/SkeletonModification2DTwoBoneIK.xml
+++ b/doc/classes/SkeletonModification2DTwoBoneIK.xml
@@ -65,7 +65,7 @@
</methods>
<members>
<member name="flip_bend_direction" type="bool" setter="set_flip_bend_direction" getter="get_flip_bend_direction" default="false">
- If [code]true[/code], the bones in the modification will blend outward as opposed to inwards when contracting. If [code]false[/code], the bones will bend inwards when contracting.
+ If [code]true[/code], the bones in the modification will bend outward as opposed to inwards when contracting. If [code]false[/code], the bones will bend inwards when contracting.
</member>
<member name="target_maximum_distance" type="float" setter="set_target_maximum_distance" getter="get_target_maximum_distance" default="0.0">
The maximum distance the target can be at. If the target is farther than this distance, the modification will solve as if it's at this maximum distance. When set to [code]0[/code], the modification will solve without distance constraints.
diff --git a/doc/classes/SplitContainer.xml b/doc/classes/SplitContainer.xml
index 650c396190..daafbbdd87 100644
--- a/doc/classes/SplitContainer.xml
+++ b/doc/classes/SplitContainer.xml
@@ -30,7 +30,7 @@
</methods>
<members>
<member name="collapsed" type="bool" setter="set_collapsed" getter="is_collapsed" default="false">
- If [code]true[/code], the area of the first [Control] will be collapsed and the dragger will be disabled.
+ If [code]true[/code], the dragger will be disabled and the children will be sized as if the [member split_offset] was [code]0[/code].
</member>
<member name="drag_area_highlight_in_editor" type="bool" setter="set_drag_area_highlight_in_editor" getter="is_drag_area_highlight_in_editor_enabled" default="false">
Highlights the drag area [Rect2] so you can see where it is during development. The drag area is gold if [member dragging_enabled] is [code]true[/code], and red if [code]false[/code].
diff --git a/doc/classes/StreamPeer.xml b/doc/classes/StreamPeer.xml
index ad5c5472b8..acff5cf604 100644
--- a/doc/classes/StreamPeer.xml
+++ b/doc/classes/StreamPeer.xml
@@ -59,6 +59,12 @@
Gets a single-precision float from the stream.
</description>
</method>
+ <method name="get_half">
+ <return type="float" />
+ <description>
+ Gets a half-precision float from the stream.
+ </description>
+ </method>
<method name="get_partial_data">
<return type="Array" />
<param index="0" name="bytes" type="int" />
@@ -162,6 +168,13 @@
Puts a single-precision float into the stream.
</description>
</method>
+ <method name="put_half">
+ <return type="void" />
+ <param index="0" name="value" type="float" />
+ <description>
+ Puts a half-precision float into the stream.
+ </description>
+ </method>
<method name="put_partial_data">
<return type="Array" />
<param index="0" name="data" type="PackedByteArray" />
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index 44795af473..d0512b8e1c 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -248,7 +248,7 @@
<param index="1" name="placeholder" type="String" default="&quot;{_}&quot;" />
<description>
Formats the string by replacing all occurrences of [param placeholder] with the elements of [param values].
- [param values] can be a [Dictionary], an [Array] or an [Object]. Any underscores in [param placeholder] will be replaced with the corresponding keys in advance. Array elements use their index as keys.
+ [param values] can be a [Dictionary], an [Array], or an [Object]. Any underscores in [param placeholder] will be replaced with the corresponding keys in advance. Array elements use their index as keys.
[codeblock]
# Prints "Waiting for Godot is a play by Samuel Beckett, and Godot Engine is named after it."
var use_array_values = "Waiting for {0} is a play by {1}, and {0} Engine is named after it."
@@ -265,17 +265,17 @@
[/codeblock]
When passing an [Object], the property names from [method Object.get_property_list] are used as keys.
[codeblock]
- # Prints: Visible true, position (0, 0).
+ # Prints "Visible true, position (0, 0)"
var node = Node2D.new()
print("Visible {visible}, position {position}".format(node))
[/codeblock]
See also the [url=$DOCS_URL/tutorials/scripting/gdscript/gdscript_format_string.html]GDScript format string[/url] tutorial.
- [b]Note:[/b] The replacement of placeholders is not done all at once, instead each placeholder is replaced in the order they are passed, this means that if one of the replacement strings contains a key it will also be replaced. This can be very powerful, but can also cause unexpected results if you are not careful. If you do not need to perform replacement in the replacement strings, make sure your replacements do not contain placeholders to ensure reliable results.
+ [b]Note:[/b] Each replacement is done sequentially for each element of [param values], [b]not[/b] all at once. This means that if any element is inserted and it contains another placeholder, it may be changed by the next replacement. While this can be very useful, it often causes unexpected results. If not necessary, make sure [param values]'s elements do not contain placeholders.
[codeblock]
- print("{0} {1}".format(["{1}", "x"])) # Prints "x x".
- print("{0} {1}".format(["x", "{0}"])) # Prints "x {0}".
- print("{foo} {bar}".format({"foo": "{bar}", "bar": "baz"})) # Prints "baz baz".
- print("{foo} {bar}".format({"bar": "baz", "foo": "{bar}"})) # Prints "{bar} baz".
+ print("{0} {1}".format(["{1}", "x"])) # Prints "x x".
+ print("{0} {1}".format(["x", "{0}"])) # Prints "x {0}".
+ print("{a} {b}".format({"a": "{b}", "b": "c"})) # Prints "c c".
+ print("{a} {b}".format({"b": "c", "a": "{b}"})) # Prints "{b} c".
[/codeblock]
[b]Note:[/b] In C#, it's recommended to [url=https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated]interpolate strings with "$"[/url], instead.
</description>
@@ -887,7 +887,7 @@
<return type="float" />
<param index="0" name="text" type="String" />
<description>
- Returns the similarity index ([url=https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient]Sorensen-Dice coefficient[/url]) of this string compared to another. A result of [code]1.0[/code] means totally similar, while [code]0.0[/code] means totally dissimilar.
+ Returns the similarity index ([url=https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient]Sørensen-Dice coefficient[/url]) of this string compared to another. A result of [code]1.0[/code] means totally similar, while [code]0.0[/code] means totally dissimilar.
[codeblock]
print("ABC123".similarity("ABC123")) # Prints 1.0
print("ABC123".similarity("XYZ456")) # Prints 0.0
diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml
index 3a2b492496..e561ef54fa 100644
--- a/doc/classes/StringName.xml
+++ b/doc/classes/StringName.xml
@@ -231,7 +231,7 @@
<param index="1" name="placeholder" type="String" default="&quot;{_}&quot;" />
<description>
Formats the string by replacing all occurrences of [param placeholder] with the elements of [param values].
- [param values] can be a [Dictionary] or an [Array]. Any underscores in [param placeholder] will be replaced with the corresponding keys in advance. Array elements use their index as keys.
+ [param values] can be a [Dictionary], an [Array], or an [Object]. Any underscores in [param placeholder] will be replaced with the corresponding keys in advance. Array elements use their index as keys.
[codeblock]
# Prints "Waiting for Godot is a play by Samuel Beckett, and Godot Engine is named after it."
var use_array_values = "Waiting for {0} is a play by {1}, and {0} Engine is named after it."
@@ -246,7 +246,20 @@
print("User {} is {}.".format([42, "Godot"], "{}"))
print("User {id} is {name}.".format([["id", 42], ["name", "Godot"]]))
[/codeblock]
+ When passing an [Object], the property names from [method Object.get_property_list] are used as keys.
+ [codeblock]
+ # Prints "Visible true, position (0, 0)"
+ var node = Node2D.new()
+ print("Visible {visible}, position {position}".format(node))
+ [/codeblock]
See also the [url=$DOCS_URL/tutorials/scripting/gdscript/gdscript_format_string.html]GDScript format string[/url] tutorial.
+ [b]Note:[/b] Each replacement is done sequentially for each element of [param values], [b]not[/b] all at once. This means that if any element is inserted and it contains another placeholder, it may be changed by the next replacement. While this can be very useful, it often causes unexpected results. If not necessary, make sure [param values]'s elements do not contain placeholders.
+ [codeblock]
+ print("{0} {1}".format(["{1}", "x"])) # Prints "x x".
+ print("{0} {1}".format(["x", "{0}"])) # Prints "x {0}".
+ print("{a} {b}".format({"a": "{b}", "b": "c"})) # Prints "c c".
+ print("{a} {b}".format({"b": "c", "a": "{b}"})) # Prints "{b} c".
+ [/codeblock]
[b]Note:[/b] In C#, it's recommended to [url=https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated]interpolate strings with "$"[/url], instead.
</description>
</method>
@@ -299,7 +312,7 @@
<param index="0" name="delimiter" type="String" />
<param index="1" name="slice" type="int" />
<description>
- Splits the string using a [param delimiter] and returns the substring at index [param slice]. Returns an empty string if the [param slice] does not exist.
+ Splits the string using a [param delimiter] and returns the substring at index [param slice]. Returns the original string if [param delimiter] does not occur in the string. Returns an empty string if the [param slice] does not exist.
This is faster than [method split], if you only need one substring.
[codeblock]
print("i/am/example/hi".get_slice("/", 2)) # Prints "example"
@@ -782,7 +795,7 @@
<return type="float" />
<param index="0" name="text" type="String" />
<description>
- Returns the similarity index ([url=https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient]Sorensen-Dice coefficient[/url]) of this string compared to another. A result of [code]1.0[/code] means totally similar, while [code]0.0[/code] means totally dissimilar.
+ Returns the similarity index ([url=https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient]Sørensen-Dice coefficient[/url]) of this string compared to another. A result of [code]1.0[/code] means totally similar, while [code]0.0[/code] means totally dissimilar.
[codeblock]
print("ABC123".similarity("ABC123")) # Prints 1.0
print("ABC123".similarity("XYZ456")) # Prints 0.0
@@ -871,7 +884,7 @@
<method name="to_ascii_buffer" qualifiers="const">
<return type="PackedByteArray" />
<description>
- Converts the string to an [url=https://en.wikipedia.org/wiki/ASCII]ASCII[/url]/Latin-1 encoded [PackedByteArray]. This method is slightly faster than [method to_utf8_buffer], but replaces all unsupported characters with spaces.
+ Converts the string to an [url=https://en.wikipedia.org/wiki/ASCII]ASCII[/url]/Latin-1 encoded [PackedByteArray]. This method is slightly faster than [method to_utf8_buffer], but replaces all unsupported characters with spaces. This is the inverse of [method PackedByteArray.get_string_from_ascii].
</description>
</method>
<method name="to_camel_case" qualifiers="const">
@@ -885,11 +898,11 @@
<description>
Converts the string representing a decimal number into a [float]. This method stops on the first non-number character, except the first decimal point ([code].[/code]) and the exponent letter ([code]e[/code]). See also [method is_valid_float].
[codeblock]
- var a = "12.35".to_float() # a is 12.35
- var b = "1.2.3".to_float() # b is 1.2
- var c = "12xy3".to_float() # c is 12.0
- var d = "1e3".to_float() # d is 1000.0
- var e = "Hello!".to_int() # e is 0.0
+ var a = "12.35".to_float() # a is 12.35
+ var b = "1.2.3".to_float() # b is 1.2
+ var c = "12xy3".to_float() # c is 12.0
+ var d = "1e3".to_float() # d is 1000.0
+ var e = "Hello!".to_float() # e is 0.0
[/codeblock]
</description>
</method>
@@ -945,25 +958,25 @@
<method name="to_utf8_buffer" qualifiers="const">
<return type="PackedByteArray" />
<description>
- Converts the string to a [url=https://en.wikipedia.org/wiki/UTF-8]UTF-8[/url] encoded [PackedByteArray]. This method is slightly slower than [method to_ascii_buffer], but supports all UTF-8 characters. For most cases, prefer using this method.
+ Converts the string to a [url=https://en.wikipedia.org/wiki/UTF-8]UTF-8[/url] encoded [PackedByteArray]. This method is slightly slower than [method to_ascii_buffer], but supports all UTF-8 characters. For most cases, prefer using this method. This is the inverse of [method PackedByteArray.get_string_from_utf8].
</description>
</method>
<method name="to_utf16_buffer" qualifiers="const">
<return type="PackedByteArray" />
<description>
- Converts the string to a [url=https://en.wikipedia.org/wiki/UTF-16]UTF-16[/url] encoded [PackedByteArray].
+ Converts the string to a [url=https://en.wikipedia.org/wiki/UTF-16]UTF-16[/url] encoded [PackedByteArray]. This is the inverse of [method PackedByteArray.get_string_from_utf16].
</description>
</method>
<method name="to_utf32_buffer" qualifiers="const">
<return type="PackedByteArray" />
<description>
- Converts the string to a [url=https://en.wikipedia.org/wiki/UTF-32]UTF-32[/url] encoded [PackedByteArray].
+ Converts the string to a [url=https://en.wikipedia.org/wiki/UTF-32]UTF-32[/url] encoded [PackedByteArray]. This is the inverse of [method PackedByteArray.get_string_from_utf32].
</description>
</method>
<method name="to_wchar_buffer" qualifiers="const">
<return type="PackedByteArray" />
<description>
- Converts the string to a [url=https://en.wikipedia.org/wiki/Wide_character]wide character[/url] ([code]wchar_t[/code], UTF-16 on Windows, UTF-32 on other platforms) encoded [PackedByteArray].
+ Converts the string to a [url=https://en.wikipedia.org/wiki/Wide_character]wide character[/url] ([code]wchar_t[/code], UTF-16 on Windows, UTF-32 on other platforms) encoded [PackedByteArray]. This is the inverse of [method PackedByteArray.get_string_from_wchar].
</description>
</method>
<method name="trim_prefix" qualifiers="const">
@@ -990,7 +1003,7 @@
<method name="uri_decode" qualifiers="const">
<return type="String" />
<description>
- Decodes the string from its URL-encoded format. This method is meant to properly decode the parameters in a URL when receiving an HTTP request.
+ Decodes the string from its URL-encoded format. This method is meant to properly decode the parameters in a URL when receiving an HTTP request. See also [method uri_encode].
[codeblocks]
[gdscript]
var url = "$DOCS_URL/?highlight=Godot%20Engine%3%docs"
@@ -1006,7 +1019,7 @@
<method name="uri_encode" qualifiers="const">
<return type="String" />
<description>
- Encodes the string to URL-friendly format. This method is meant to properly encode the parameters in a URL when sending an HTTP request.
+ Encodes the string to URL-friendly format. This method is meant to properly encode the parameters in a URL when sending an HTTP request. See also [method uri_decode].
[codeblocks]
[gdscript]
var prefix = "$DOCS_URL/?highlight="
diff --git a/doc/classes/StyleBoxTexture.xml b/doc/classes/StyleBoxTexture.xml
index 14bceb4d4c..07d4b13f36 100644
--- a/doc/classes/StyleBoxTexture.xml
+++ b/doc/classes/StyleBoxTexture.xml
@@ -80,9 +80,9 @@
Modulates the color of the texture when this style box is drawn.
</member>
<member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect" default="Rect2(0, 0, 0, 0)">
- Species a sub-region of the texture to use.
- This is equivalent to first wrapping the texture in an [AtlasTexture] with the same region.
- If empty ([code]Rect2(0, 0, 0, 0)[/code]), the whole texture will be used.
+ The region to use from the [member texture].
+ This is equivalent to first wrapping the [member texture] in an [AtlasTexture] with the same region.
+ If empty ([code]Rect2(0, 0, 0, 0)[/code]), the whole [member texture] is used.
</member>
<member name="texture" type="Texture2D" setter="set_texture" getter="get_texture">
The texture to use when drawing this style box.
diff --git a/doc/classes/SubViewportContainer.xml b/doc/classes/SubViewportContainer.xml
index b7d097cc91..310f235abf 100644
--- a/doc/classes/SubViewportContainer.xml
+++ b/doc/classes/SubViewportContainer.xml
@@ -20,6 +20,10 @@
</method>
</methods>
<members>
+ <member name="consume_drag_and_drop" type="bool" setter="set_consume_drag_and_drop" getter="is_consume_drag_and_drop_enabled" default="false">
+ If [code]false[/code], the [SubViewportContainer] is not available as a drop target in drag-and-drop operations, and instead the [Control] nodes inside its [Viewport] children are potential drop targets.
+ If [code]true[/code], the [SubViewportContainer] itself will be considered as a drop target in drag-and-drop operations, preventing the [Control] nodes inside its [Viewport] children from becoming drop targets.
+ </member>
<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="1" />
<member name="stretch" type="bool" setter="set_stretch" getter="is_stretch_enabled" default="false">
If [code]true[/code], the sub-viewport will be automatically resized to the control's size.
diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml
index 9c1525d8f8..9265e6b345 100644
--- a/doc/classes/SurfaceTool.xml
+++ b/doc/classes/SurfaceTool.xml
@@ -140,7 +140,7 @@
<param index="0" name="flip" type="bool" default="false" />
<description>
Generates normals from vertices so you do not have to do it manually. If [param flip] is [code]true[/code], the resulting normals will be inverted. [method generate_normals] should be called [i]after[/i] generating geometry and [i]before[/i] committing the mesh using [method commit] or [method commit_to_arrays]. For correct display of normal-mapped surfaces, you will also have to generate tangents using [method generate_tangents].
- [b]Note:[/b] [method generate_normals] only works if the primitive type to be set to [constant Mesh.PRIMITIVE_TRIANGLES].
+ [b]Note:[/b] [method generate_normals] only works if the primitive type is set to [constant Mesh.PRIMITIVE_TRIANGLES].
[b]Note:[/b] [method generate_normals] takes smooth groups into account. To generate smooth normals, set the smooth group to a value greater than or equal to [code]0[/code] using [method set_smooth_group] or leave the smooth group at the default of [code]0[/code]. To generate flat normals, set the smooth group to [code]-1[/code] using [method set_smooth_group] prior to adding vertices.
</description>
</method>
diff --git a/doc/classes/SyntaxHighlighter.xml b/doc/classes/SyntaxHighlighter.xml
index 27cee26c50..22d20d24e5 100644
--- a/doc/classes/SyntaxHighlighter.xml
+++ b/doc/classes/SyntaxHighlighter.xml
@@ -41,11 +41,11 @@
<return type="Dictionary" />
<param index="0" name="line" type="int" />
<description>
- Returns syntax highlighting data for a single line. If the line is not cached, calls [method _get_line_syntax_highlighting] to calculate the data.
- The return [Dictionary] is column number to [Dictionary]. The column number notes the start of a region, the region will end if another region is found, or at the end of the line. The nested [Dictionary] contains the data for that region, currently only the key "color" is supported.
- [b]Example return:[/b]
+ Returns the syntax highlighting data for the line at index [param line]. If the line is not cached, calls [method _get_line_syntax_highlighting] first to calculate the data.
+ Each entry is a column number containing a nested [Dictionary]. The column number denotes the start of a region, the region will end if another region is found, or at the end of the line. The nested [Dictionary] contains the data for that region. Currently only the key [code]"color"[/code] is supported.
+ [b]Example:[/b] Possible return value. This means columns [code]0[/code] to [code]4[/code] should be red, and columns [code]5[/code] to the end of the line should be green:
[codeblock]
- var color_map = {
+ {
0: {
"color": Color(1, 0, 0)
},
@@ -54,7 +54,6 @@
}
}
[/codeblock]
- This will color columns 0-4 red, and columns 5-eol in green.
</description>
</method>
<method name="get_text_edit" qualifiers="const">
diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index 7a4bef5747..b884fa5958 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -124,7 +124,6 @@
<return type="void" />
<description>
Starts an edit for multiple carets. The edit must be ended with [method end_multicaret_edit]. Multicaret edits can be used to edit text at multiple carets and delay merging the carets until the end, so the caret indexes aren't affected immediately. [method begin_multicaret_edit] and [method end_multicaret_edit] can be nested, and the merge will happen at the last [method end_multicaret_edit].
- Example usage:
[codeblock]
begin_complex_operation()
begin_multicaret_edit()
@@ -266,7 +265,7 @@
<return type="int" />
<param index="0" name="line" type="int" />
<description>
- Returns the first column containing a non-whitespace character.
+ Returns the first column containing a non-whitespace character on the given line. If there is only whitespace, returns the number of characters.
</description>
</method>
<method name="get_first_visible_line" qualifiers="const">
@@ -312,7 +311,7 @@
<return type="int" />
<param index="0" name="line" type="int" />
<description>
- Returns the number of spaces and [code]tab * tab_size[/code] before the first char.
+ Returns the indent level of the given line. This is the number of spaces and tabs at the beginning of the line, with the tabs taking the tab size into account (see [method get_tab_size]).
</description>
</method>
<method name="get_last_full_visible_line" qualifiers="const">
@@ -344,7 +343,7 @@
<return type="Color" />
<param index="0" name="line" type="int" />
<description>
- Returns the current background color of the line. [code]Color(0, 0, 0, 0)[/code] is returned if no color is set.
+ Returns the custom background color of the given line. If no color is set, returns [code]Color(0, 0, 0, 0)[/code].
</description>
</method>
<method name="get_line_column_at_pos" qualifiers="const">
@@ -429,7 +428,7 @@
<param index="0" name="line" type="int" />
<param index="1" name="column" type="int" />
<description>
- Returns the wrap index of the given line column.
+ Returns the wrap index of the given column on the given line. This ranges from [code]0[/code] to [method get_line_wrap_count].
</description>
</method>
<method name="get_line_wrapped_text" qualifiers="const">
@@ -656,7 +655,7 @@
<method name="get_total_visible_line_count" qualifiers="const">
<return type="int" />
<description>
- Returns the number of lines that may be drawn.
+ Returns the total number of lines in the text. This includes wrapped lines and excludes folded lines. If [member wrap_mode] is set to [constant LINE_WRAPPING_NONE] and no lines are folded (see [method CodeEdit.is_line_folded]) then this is equivalent to [method get_line_count]. See [method get_visible_line_count_in_range] for a limited range of lines.
</description>
</method>
<method name="get_v_scroll_bar" qualifiers="const">
@@ -674,7 +673,7 @@
<method name="get_visible_line_count" qualifiers="const">
<return type="int" />
<description>
- Returns the number of visible lines, including wrapped text.
+ Returns the number of lines that can visually fit, rounded down, based on this control's height.
</description>
</method>
<method name="get_visible_line_count_in_range" qualifiers="const">
@@ -682,7 +681,7 @@
<param index="0" name="from_line" type="int" />
<param index="1" name="to_line" type="int" />
<description>
- Returns the total number of visible + wrapped lines between the two lines.
+ Returns the total number of lines between [param from_line] and [param to_line] (inclusive) in the text. This includes wrapped lines and excludes folded lines. If the range covers all lines it is equivalent to [method get_total_visible_line_count].
</description>
</method>
<method name="get_word_at_pos" qualifiers="const">
@@ -764,7 +763,8 @@
<return type="bool" />
<param index="0" name="caret_index" type="int" default="0" />
<description>
- Returns [code]true[/code] if the caret is visible on the screen.
+ Returns [code]true[/code] if the caret is visible, [code]false[/code] otherwise. A caret will be considered hidden if it is outside the scrollable area when scrolling is enabled.
+ [b]Note:[/b] [method is_caret_visible] does not account for a caret being off-screen if it is still within the scrollable area. It will return [code]true[/code] even if the caret is off-screen as long as it meets [TextEdit]'s own conditions for being visible. This includes uses of [member scroll_fit_content_width] and [member scroll_fit_content_height] that cause the [TextEdit] to expand beyond the viewport's bounds.
</description>
</method>
<method name="is_dragging_cursor" qualifiers="const">
@@ -777,21 +777,21 @@
<return type="bool" />
<param index="0" name="gutter" type="int" />
<description>
- Returns whether the gutter is clickable.
+ Returns [code]true[/code] if the gutter at the given index is clickable. See [method set_gutter_clickable].
</description>
</method>
<method name="is_gutter_drawn" qualifiers="const">
<return type="bool" />
<param index="0" name="gutter" type="int" />
<description>
- Returns whether the gutter is currently drawn.
+ Returns [code]true[/code] if the gutter at the given index is currently drawn. See [method set_gutter_draw].
</description>
</method>
<method name="is_gutter_overwritable" qualifiers="const">
<return type="bool" />
<param index="0" name="gutter" type="int" />
<description>
- Returns whether the gutter is overwritable.
+ Returns [code]true[/code] if the gutter at the given index is overwritable. See [method set_gutter_overwritable].
</description>
</method>
<method name="is_in_mulitcaret_edit" qualifiers="const">
@@ -805,7 +805,7 @@
<param index="0" name="line" type="int" />
<param index="1" name="gutter" type="int" />
<description>
- Returns whether the gutter on the given line is clickable.
+ Returns [code]true[/code] if the gutter at the given index on the given line is clickable. See [method set_line_gutter_clickable].
</description>
</method>
<method name="is_line_wrapped" qualifiers="const">
@@ -818,7 +818,7 @@
<method name="is_menu_visible" qualifiers="const">
<return type="bool" />
<description>
- Returns whether the menu is visible. Use this instead of [code]get_menu().visible[/code] to improve performance (so the creation of the menu is avoided).
+ Returns [code]true[/code] if the menu is visible. Use this instead of [code]get_menu().visible[/code] to improve performance (so the creation of the menu is avoided). See [method get_menu].
</description>
</method>
<method name="is_mouse_over_selection" qualifiers="const">
@@ -826,13 +826,13 @@
<param index="0" name="edges" type="bool" />
<param index="1" name="caret_index" type="int" default="-1" />
<description>
- Returns whether the mouse is over selection. If [param edges] is [code]true[/code], the edges are considered part of the selection.
+ Returns [code]true[/code] if the mouse is over a selection. If [param edges] is [code]true[/code], the edges are considered part of the selection.
</description>
</method>
<method name="is_overtype_mode_enabled" qualifiers="const">
<return type="bool" />
<description>
- Returns whether the user is in overtype mode.
+ Returns [code]true[/code] if overtype mode is enabled. See [method set_overtype_mode_enabled].
</description>
</method>
<method name="menu_option">
@@ -847,7 +847,7 @@
<param index="0" name="from_line" type="int" />
<param index="1" name="to_line" type="int" />
<description>
- Merge the gutters from [param from_line] into [param to_line]. Only overwritable gutters will be copied.
+ Merge the gutters from [param from_line] into [param to_line]. Only overwritable gutters will be copied. See [method set_gutter_overwritable].
</description>
</method>
<method name="merge_overlapping_carets">
@@ -898,7 +898,7 @@
<return type="void" />
<param index="0" name="gutter" type="int" />
<description>
- Removes the gutter from this [TextEdit].
+ Removes the gutter at the given index.
</description>
</method>
<method name="remove_line_at">
@@ -1013,7 +1013,7 @@
<param index="0" name="gutter" type="int" />
<param index="1" name="clickable" type="bool" />
<description>
- Sets the gutter as clickable. This will change the mouse cursor to a pointing hand when hovering over the gutter.
+ If [code]true[/code], the mouse cursor will change to a pointing hand ([constant Control.CURSOR_POINTING_HAND]) when hovering over the gutter at the given index. See [method is_gutter_clickable] and [method set_line_gutter_clickable].
</description>
</method>
<method name="set_gutter_custom_draw">
@@ -1021,7 +1021,7 @@
<param index="0" name="column" type="int" />
<param index="1" name="draw_callback" type="Callable" />
<description>
- Set a custom draw method for the gutter. The callback method must take the following args: [code]line: int, gutter: int, Area: Rect2[/code]. This only works when the gutter type is [constant GUTTER_TYPE_CUSTOM] (see [method set_gutter_type]).
+ Set a custom draw callback for the gutter at the given index. [param draw_callback] must take the following arguments: A line index [int], a gutter index [int], and an area [Rect2]. This callback only works when the gutter type is [constant GUTTER_TYPE_CUSTOM] (see [method set_gutter_type]).
</description>
</method>
<method name="set_gutter_draw">
@@ -1029,7 +1029,7 @@
<param index="0" name="gutter" type="int" />
<param index="1" name="draw" type="bool" />
<description>
- Sets whether the gutter should be drawn.
+ If [code]true[/code], the gutter at the given index is drawn. The gutter type ([method set_gutter_type]) determines how it is drawn. See [method is_gutter_drawn].
</description>
</method>
<method name="set_gutter_name">
@@ -1037,7 +1037,7 @@
<param index="0" name="gutter" type="int" />
<param index="1" name="name" type="String" />
<description>
- Sets the name of the gutter.
+ Sets the name of the gutter at the given index.
</description>
</method>
<method name="set_gutter_overwritable">
@@ -1045,7 +1045,7 @@
<param index="0" name="gutter" type="int" />
<param index="1" name="overwritable" type="bool" />
<description>
- Sets the gutter to overwritable. See [method merge_gutters].
+ If [code]true[/code], the line data of the gutter at the given index can be overridden when using [method merge_gutters]. See [method is_gutter_overwritable].
</description>
</method>
<method name="set_gutter_type">
@@ -1053,7 +1053,7 @@
<param index="0" name="gutter" type="int" />
<param index="1" name="type" type="int" enum="TextEdit.GutterType" />
<description>
- Sets the type of gutter. Gutters can contain icons, text, or custom visuals. See [enum TextEdit.GutterType] for options.
+ Sets the type of gutter at the given index. Gutters can contain icons, text, or custom visuals. See [enum TextEdit.GutterType] for options.
</description>
</method>
<method name="set_gutter_width">
@@ -1061,7 +1061,7 @@
<param index="0" name="gutter" type="int" />
<param index="1" name="width" type="int" />
<description>
- Set the width of the gutter.
+ Set the width of the gutter at the given index.
</description>
</method>
<method name="set_line">
@@ -1102,7 +1102,7 @@
<param index="0" name="line" type="int" />
<param index="1" name="color" type="Color" />
<description>
- Sets the current background color of the line. Set to [code]Color(0, 0, 0, 0)[/code] for no color.
+ Sets the custom background color of the given line. If transparent, this color is applied on top of the default background color (See [theme_item background_color]). If set to [code]Color(0, 0, 0, 0)[/code], no additional color is applied.
</description>
</method>
<method name="set_line_gutter_clickable">
@@ -1111,7 +1111,7 @@
<param index="1" name="gutter" type="int" />
<param index="2" name="clickable" type="bool" />
<description>
- If [param clickable] is [code]true[/code], makes the [param gutter] on [param line] clickable. See [signal gutter_clicked].
+ If [param clickable] is [code]true[/code], makes the [param gutter] on the given [param line] clickable. This is like [method set_gutter_clickable], but for a single line. If [method is_gutter_clickable] is [code]true[/code], this will not have any effect. See [method is_line_gutter_clickable] and [signal gutter_clicked].
</description>
</method>
<method name="set_line_gutter_icon">
@@ -1154,7 +1154,7 @@
<return type="void" />
<param index="0" name="enabled" type="bool" />
<description>
- If [code]true[/code], sets the user into overtype mode. When the user types in this mode, it will override existing text.
+ If [code]true[/code], enables overtype mode. In this mode, typing overrides existing text instead of inserting text. The [member ProjectSettings.input/ui_text_toggle_insert_mode] action toggles overtype mode. See [method is_overtype_mode_enabled].
</description>
</method>
<method name="set_search_flags">
@@ -1269,7 +1269,7 @@
If [code]false[/code], the context menu ignores mouse location.
</member>
<member name="caret_multiple" type="bool" setter="set_multiple_carets_enabled" getter="is_multiple_carets_enabled" default="true">
- Sets if multiple carets are allowed.
+ If [code]true[/code], multiple carets are allowed. Left-clicking with [kbd]Alt[/kbd] adds a new caret. See [method add_caret] and [method get_caret_count].
</member>
<member name="caret_type" type="int" setter="set_caret_type" getter="get_caret_type" enum="TextEdit.CaretType" default="0">
Set the type of caret to draw.
diff --git a/doc/classes/TextureProgressBar.xml b/doc/classes/TextureProgressBar.xml
index d3e334ef55..c68b521da9 100644
--- a/doc/classes/TextureProgressBar.xml
+++ b/doc/classes/TextureProgressBar.xml
@@ -42,6 +42,7 @@
</member>
<member name="radial_initial_angle" type="float" setter="set_radial_initial_angle" getter="get_radial_initial_angle" default="0.0">
Starting angle for the fill of [member texture_progress] if [member fill_mode] is [constant FILL_CLOCKWISE], [constant FILL_COUNTER_CLOCKWISE], or [constant FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE]. When the node's [code]value[/code] is equal to its [code]min_value[/code], the texture doesn't show up at all. When the [code]value[/code] increases, the texture fills and tends towards [member radial_fill_degrees].
+ [b]Note:[/b] [member radial_initial_angle] is wrapped between [code]0[/code] and [code]360[/code] degrees (inclusive).
</member>
<member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" enum="Control.SizeFlags" is_bitfield="true" default="1" />
<member name="step" type="float" setter="set_step" getter="get_step" overrides="Range" default="1.0" />
diff --git a/doc/classes/TileMapLayer.xml b/doc/classes/TileMapLayer.xml
index e814d76b73..43708ca142 100644
--- a/doc/classes/TileMapLayer.xml
+++ b/doc/classes/TileMapLayer.xml
@@ -135,7 +135,7 @@
<return type="Vector2i[]" />
<param index="0" name="coords" type="Vector2i" />
<description>
- Returns the list of all neighboring cells to the one at [param coords].
+ Returns the list of all neighboring cells to the one at [param coords]. Any neighboring cell is one that is touching edges, so for a square cell 4 cells would be returned, for a hexagon 6 cells are returned.
</description>
</method>
<method name="get_used_cells" qualifiers="const">
diff --git a/doc/classes/TouchScreenButton.xml b/doc/classes/TouchScreenButton.xml
index 5052518583..faeaaba5b6 100644
--- a/doc/classes/TouchScreenButton.xml
+++ b/doc/classes/TouchScreenButton.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
TouchScreenButton allows you to create on-screen buttons for touch devices. It's intended for gameplay use, such as a unit you have to touch to move. Unlike [Button], TouchScreenButton supports multitouch out of the box. Several TouchScreenButtons can be pressed at the same time with touch input.
- This node inherits from [Node2D]. Unlike with [Control] nodes, you cannot set anchors on it. If you want to create menus or user interfaces, you may want to use [Button] nodes instead. To make button nodes react to touch events, you can enable the Emulate Mouse option in the Project Settings.
+ This node inherits from [Node2D]. Unlike with [Control] nodes, you cannot set anchors on it. If you want to create menus or user interfaces, you may want to use [Button] nodes instead. To make button nodes react to touch events, you can enable [member ProjectSettings.input_devices/pointing/emulate_mouse_from_touch] in the Project Settings.
You can configure TouchScreenButton to be visible only on touch devices, helping you develop your game both for desktop and mobile devices.
</description>
<tutorials>
diff --git a/doc/classes/Transform3D.xml b/doc/classes/Transform3D.xml
index 0f943c7dd1..98e9d56adb 100644
--- a/doc/classes/Transform3D.xml
+++ b/doc/classes/Transform3D.xml
@@ -129,7 +129,7 @@
<param index="1" name="angle" type="float" />
<description>
Returns a copy of this transform rotated around the given [param axis] by the given [param angle] (in radians).
- The [param axis] must be a normalized vector.
+ The [param axis] must be a normalized vector in the transform's local coordinate system. For example, to rotate around the local X-axis, use [constant Vector3.RIGHT].
This method is an optimized version of multiplying the given transform [code]X[/code] with a corresponding rotation transform [code]R[/code] from the right, i.e., [code]X * R[/code].
This can be seen as transforming with respect to the local frame.
</description>
diff --git a/doc/classes/TranslationServer.xml b/doc/classes/TranslationServer.xml
index 69ca984f67..f30a1da014 100644
--- a/doc/classes/TranslationServer.xml
+++ b/doc/classes/TranslationServer.xml
@@ -160,8 +160,9 @@
<method name="standardize_locale" qualifiers="const">
<return type="String" />
<param index="0" name="locale" type="String" />
+ <param index="1" name="add_defaults" type="bool" default="false" />
<description>
- Returns a [param locale] string standardized to match known locales (e.g. [code]en-US[/code] would be matched to [code]en_US[/code]).
+ Returns a [param locale] string standardized to match known locales (e.g. [code]en-US[/code] would be matched to [code]en_US[/code]). If [param add_defaults] is [code]true[/code], the locale may have a default script or country added.
</description>
</method>
<method name="translate" qualifiers="const">
diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml
index 86a8130acc..147d9fa4bd 100644
--- a/doc/classes/Tween.xml
+++ b/doc/classes/Tween.xml
@@ -218,8 +218,14 @@
<return type="Tween" />
<param index="0" name="ease" type="int" enum="Tween.EaseType" />
<description>
- Sets the default ease type for [PropertyTweener]s and [MethodTweener]s animated by this [Tween].
- If not specified, the default value is [constant EASE_IN_OUT].
+ Sets the default ease type for [PropertyTweener]s and [MethodTweener]s appended after this method.
+ Before this method is called, the default ease type is [constant EASE_IN_OUT].
+ [codeblock]
+ var tween = create_tween()
+ tween.tween_property(self, "position", Vector2(300, 0), 0.5) # Uses EASE_IN_OUT.
+ tween.set_ease(Tween.EASE_IN)
+ tween.tween_property(self, "rotation_degrees", 45.0, 0.5) # Uses EASE_IN.
+ [/codeblock]
</description>
</method>
<method name="set_loops">
@@ -271,14 +277,36 @@
<return type="Tween" />
<param index="0" name="trans" type="int" enum="Tween.TransitionType" />
<description>
- Sets the default transition type for [PropertyTweener]s and [MethodTweener]s animated by this [Tween].
- If not specified, the default value is [constant TRANS_LINEAR].
+ Sets the default transition type for [PropertyTweener]s and [MethodTweener]s appended after this method.
+ Before this method is called, the default transition type is [constant TRANS_LINEAR].
+ [codeblock]
+ var tween = create_tween()
+ tween.tween_property(self, "position", Vector2(300, 0), 0.5) # Uses TRANS_LINEAR.
+ tween.set_trans(Tween.TRANS_SINE)
+ tween.tween_property(self, "rotation_degrees", 45.0, 0.5) # Uses TRANS_SINE.
+ [/codeblock]
</description>
</method>
<method name="stop">
<return type="void" />
<description>
Stops the tweening and resets the [Tween] to its initial state. This will not remove any appended [Tweener]s.
+ [b]Note:[/b] This does [i]not[/i] reset targets of [PropertyTweener]s to their values when the [Tween] first started.
+ [codeblock]
+ var tween = create_tween()
+
+ # Will move from 0 to 500 over 1 second.
+ position.x = 0.0
+ tween.tween_property(self, "position:x", 500, 1.0)
+
+ # Will be at (about) 250 when the timer finishes.
+ await get_tree().create_timer(0.5).timeout
+
+ # Will now move from (about) 250 to 500 over 1 second,
+ # thus at half the speed as before.
+ tween.stop()
+ tween.play()
+ [/codeblock]
[b]Note:[/b] If a Tween is stopped and not bound to any node, it will exist indefinitely until manually started or invalidated. If you lose a reference to such Tween, you can retrieve it using [method SceneTree.get_processed_tweens].
</description>
</method>
diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml
index 78183ae36c..c03262bb33 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -424,10 +424,10 @@
</member>
</members>
<constants>
- <constant name="AXIS_X" value="0">
+ <constant name="AXIS_X" value="0" enum="Axis">
Enumerated value for the X axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
- <constant name="AXIS_Y" value="1">
+ <constant name="AXIS_Y" value="1" enum="Axis">
Enumerated value for the Y axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
<constant name="ZERO" value="Vector2(0, 0)">
diff --git a/doc/classes/Vector2i.xml b/doc/classes/Vector2i.xml
index 4afc62e038..53c7c92ca3 100644
--- a/doc/classes/Vector2i.xml
+++ b/doc/classes/Vector2i.xml
@@ -170,10 +170,10 @@
</member>
</members>
<constants>
- <constant name="AXIS_X" value="0">
+ <constant name="AXIS_X" value="0" enum="Axis">
Enumerated value for the X axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
- <constant name="AXIS_Y" value="1">
+ <constant name="AXIS_Y" value="1" enum="Axis">
Enumerated value for the Y axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
<constant name="ZERO" value="Vector2i(0, 0)">
diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml
index c04fcd0b24..4ab3140eb6 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -421,13 +421,13 @@
</member>
</members>
<constants>
- <constant name="AXIS_X" value="0">
+ <constant name="AXIS_X" value="0" enum="Axis">
Enumerated value for the X axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
- <constant name="AXIS_Y" value="1">
+ <constant name="AXIS_Y" value="1" enum="Axis">
Enumerated value for the Y axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
- <constant name="AXIS_Z" value="2">
+ <constant name="AXIS_Z" value="2" enum="Axis">
Enumerated value for the Z axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
<constant name="ZERO" value="Vector3(0, 0, 0)">
diff --git a/doc/classes/Vector3i.xml b/doc/classes/Vector3i.xml
index df4624dbb1..7fe469aec0 100644
--- a/doc/classes/Vector3i.xml
+++ b/doc/classes/Vector3i.xml
@@ -168,13 +168,13 @@
</member>
</members>
<constants>
- <constant name="AXIS_X" value="0">
+ <constant name="AXIS_X" value="0" enum="Axis">
Enumerated value for the X axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
- <constant name="AXIS_Y" value="1">
+ <constant name="AXIS_Y" value="1" enum="Axis">
Enumerated value for the Y axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
- <constant name="AXIS_Z" value="2">
+ <constant name="AXIS_Z" value="2" enum="Axis">
Enumerated value for the Z axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
<constant name="ZERO" value="Vector3i(0, 0, 0)">
diff --git a/doc/classes/Vector4.xml b/doc/classes/Vector4.xml
index f70c59fbef..8fa17b57e6 100644
--- a/doc/classes/Vector4.xml
+++ b/doc/classes/Vector4.xml
@@ -287,16 +287,16 @@
</member>
</members>
<constants>
- <constant name="AXIS_X" value="0">
+ <constant name="AXIS_X" value="0" enum="Axis">
Enumerated value for the X axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
- <constant name="AXIS_Y" value="1">
+ <constant name="AXIS_Y" value="1" enum="Axis">
Enumerated value for the Y axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
- <constant name="AXIS_Z" value="2">
+ <constant name="AXIS_Z" value="2" enum="Axis">
Enumerated value for the Z axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
- <constant name="AXIS_W" value="3">
+ <constant name="AXIS_W" value="3" enum="Axis">
Enumerated value for the W axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
<constant name="ZERO" value="Vector4(0, 0, 0, 0)">
diff --git a/doc/classes/Vector4i.xml b/doc/classes/Vector4i.xml
index b351f2ccb6..e1d65eb1b5 100644
--- a/doc/classes/Vector4i.xml
+++ b/doc/classes/Vector4i.xml
@@ -169,16 +169,16 @@
</member>
</members>
<constants>
- <constant name="AXIS_X" value="0">
+ <constant name="AXIS_X" value="0" enum="Axis">
Enumerated value for the X axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
- <constant name="AXIS_Y" value="1">
+ <constant name="AXIS_Y" value="1" enum="Axis">
Enumerated value for the Y axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
- <constant name="AXIS_Z" value="2">
+ <constant name="AXIS_Z" value="2" enum="Axis">
Enumerated value for the Z axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
- <constant name="AXIS_W" value="3">
+ <constant name="AXIS_W" value="3" enum="Axis">
Enumerated value for the W axis. Returned by [method max_axis_index] and [method min_axis_index].
</constant>
<constant name="ZERO" value="Vector4i(0, 0, 0, 0)">
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index c4319fd360..678b7690d9 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -316,7 +316,7 @@
See also [member ProjectSettings.rendering/anti_aliasing/quality/msaa_2d] and [method RenderingServer.viewport_set_msaa_2d].
</member>
<member name="msaa_3d" type="int" setter="set_msaa_3d" getter="get_msaa_3d" enum="Viewport.MSAA" default="0">
- The multisample antialiasing mode for 3D rendering. A higher number results in smoother edges at the cost of significantly worse performance. A value of [constant Viewport.MSAA_2X] or [constant Viewport.MSAA_4X] is best unless targeting very high-end systems. See also bilinear scaling 3d [member scaling_3d_mode] for supersampling, which provides higher quality but is much more expensive. This has no effect on shader-induced aliasing or texture aliasing.
+ The multisample antialiasing mode for 3D rendering. A higher number results in smoother edges at the cost of significantly worse performance. A value of [constant Viewport.MSAA_2X] or [constant Viewport.MSAA_4X] is best unless targeting very high-end systems. See also bilinear scaling 3D [member scaling_3d_mode] for supersampling, which provides higher quality but is much more expensive. This has no effect on shader-induced aliasing or texture aliasing.
See also [member ProjectSettings.rendering/anti_aliasing/quality/msaa_3d] and [method RenderingServer.viewport_set_msaa_3d].
</member>
<member name="own_world_3d" type="bool" setter="set_use_own_world_3d" getter="is_using_own_world_3d" default="false">
@@ -357,7 +357,7 @@
[b]Note:[/b] If this is set to [code]0[/code], no positional shadows will be visible at all. This can improve performance significantly on low-end systems by reducing both the CPU and GPU load (as fewer draw calls are needed to draw the scene without shadows).
</member>
<member name="scaling_3d_mode" type="int" setter="set_scaling_3d_mode" getter="get_scaling_3d_mode" enum="Viewport.Scaling3DMode" default="0">
- Sets scaling 3d mode. Bilinear scaling renders at different resolution to either undersample or supersample the viewport. FidelityFX Super Resolution 1.0, abbreviated to FSR, is an upscaling technology that produces high quality images at fast framerates by using a spatially aware upscaling algorithm. FSR is slightly more expensive than bilinear, but it produces significantly higher image quality. FSR should be used where possible.
+ Sets scaling 3D mode. Bilinear scaling renders at different resolution to either undersample or supersample the viewport. FidelityFX Super Resolution 1.0, abbreviated to FSR, is an upscaling technology that produces high quality images at fast framerates by using a spatially aware upscaling algorithm. FSR is slightly more expensive than bilinear, but it produces significantly higher image quality. FSR should be used where possible.
To control this property on the root viewport, set the [member ProjectSettings.rendering/scaling_3d/mode] project setting.
</member>
<member name="scaling_3d_scale" type="float" setter="set_scaling_3d_scale" getter="get_scaling_3d_scale" default="1.0">
@@ -555,6 +555,7 @@
</constant>
<constant name="DEBUG_DRAW_WIREFRAME" value="4" enum="DebugDraw">
Objects are displayed as wireframe models.
+ [b]Note:[/b] [method RenderingServer.set_debug_generate_wireframes] must be called before loading any meshes for wireframes to be visible when using the Compatibility renderer.
</constant>
<constant name="DEBUG_DRAW_NORMAL_BUFFER" value="5" enum="DebugDraw">
Objects are displayed without lighting information and their textures replaced by normal mapping.
diff --git a/doc/classes/VisualShaderNodeColorFunc.xml b/doc/classes/VisualShaderNodeColorFunc.xml
index edb5238325..aa2dcca1d5 100644
--- a/doc/classes/VisualShaderNodeColorFunc.xml
+++ b/doc/classes/VisualShaderNodeColorFunc.xml
@@ -40,7 +40,32 @@
return vec3(r, g, b);
[/codeblock]
</constant>
- <constant name="FUNC_MAX" value="4" enum="Function">
+ <constant name="FUNC_LINEAR_TO_SRGB" value="4" enum="Function">
+ Converts color from linear color space to sRGB color space using the following formula:
+ [codeblock]
+ vec3 c = clamp(c, vec3(0.0), vec3(1.0));
+ const vec3 a = vec3(0.055f);
+ return mix((vec3(1.0f) + a) * pow(c.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * c.rgb, lessThan(c.rgb, vec3(0.0031308f)));
+ [/codeblock]
+ The Compatibility renderer uses a simpler formula:
+ [codeblock]
+ vec3 c = input;
+ return max(vec3(1.055) * pow(c, vec3(0.416666667)) - vec3(0.055), vec3(0.0));
+ [/codeblock]
+ </constant>
+ <constant name="FUNC_SRGB_TO_LINEAR" value="5" enum="Function">
+ Converts color from sRGB color space to linear color space using the following formula:
+ [codeblock]
+ vec3 c = input;
+ return mix(pow((c.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), c.rgb * (1.0 / 12.92), lessThan(c.rgb, vec3(0.04045)));
+ [/codeblock]
+ The Compatibility renderer uses a simpler formula:
+ [codeblock]
+ vec3 c = input;
+ return c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878);
+ [/codeblock]
+ </constant>
+ <constant name="FUNC_MAX" value="6" enum="Function">
Represents the size of the [enum Function] enum.
</constant>
</constants>
diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml
index 02110f0162..424941b842 100644
--- a/doc/classes/Window.xml
+++ b/doc/classes/Window.xml
@@ -725,8 +725,6 @@
<param index="0" name="files" type="PackedStringArray" />
<description>
Emitted when files are dragged from the OS file manager and dropped in the game window. The argument is a list of file paths.
- Note that this method only works with native windows, i.e. the main window and [Window]-derived nodes when [member Viewport.gui_embed_subwindows] is disabled in the main viewport.
- Example usage:
[codeblock]
func _ready():
get_viewport().files_dropped.connect(on_files_dropped)
@@ -734,6 +732,7 @@
func on_files_dropped(files):
print(files)
[/codeblock]
+ [b]Note:[/b] This signal only works with native windows, i.e. the main window and [Window]-derived nodes when [member Viewport.gui_embed_subwindows] is disabled in the main viewport.
</description>
</signal>
<signal name="focus_entered">
diff --git a/doc/classes/XRCamera3D.xml b/doc/classes/XRCamera3D.xml
index a7904b3ada..e49e884f33 100644
--- a/doc/classes/XRCamera3D.xml
+++ b/doc/classes/XRCamera3D.xml
@@ -4,7 +4,7 @@
A camera node with a few overrules for AR/VR applied, such as location tracking.
</brief_description>
<description>
- This is a helper spatial node for our camera; note that, if stereoscopic rendering is applicable (VR-HMD), most of the camera properties are ignored, as the HMD information overrides them. The only properties that can be trusted are the near and far planes.
+ This is a helper 3D node for our camera. Note that, if stereoscopic rendering is applicable (VR-HMD), most of the camera properties are ignored, as the HMD information overrides them. The only properties that can be trusted are the near and far planes.
The position and orientation of this node is automatically updated by the XR Server to represent the location of the HMD if such tracking is available and can thus be used by game logic. Note that, in contrast to the XR Controller, the render thread has access to the most up-to-date tracking data of the HMD and the location of the XRCamera3D can lag a few milliseconds behind what is used for rendering as a result.
</description>
<tutorials>
diff --git a/doc/classes/XRController3D.xml b/doc/classes/XRController3D.xml
index 8a068661c9..508752e0ae 100644
--- a/doc/classes/XRController3D.xml
+++ b/doc/classes/XRController3D.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="XRController3D" inherits="XRNode3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- A spatial node representing a spatially-tracked controller.
+ A 3D node representing a spatially-tracked controller.
</brief_description>
<description>
- This is a helper spatial node that is linked to the tracking of controllers. It also offers several handy passthroughs to the state of buttons and such on the controllers.
+ This is a helper 3D node that is linked to the tracking of controllers. It also offers several handy passthroughs to the state of buttons and such on the controllers.
Controllers are linked by their ID. You can create controller nodes before the controllers are available. If your game always uses two controllers (one for each hand), you can predefine the controllers with ID 1 and 2; they will become active as soon as the controllers are identified. If you expect additional controllers to be used, you should react to the signals and add XRController3D nodes to your scene.
The position of the controller node is automatically updated by the [XRServer]. This makes this node ideal to add child nodes to visualize the controller.
As many XR runtimes now use a configurable action map all inputs are named.
diff --git a/doc/classes/XRNode3D.xml b/doc/classes/XRNode3D.xml
index 82f4fa4ab9..fce3708d9a 100644
--- a/doc/classes/XRNode3D.xml
+++ b/doc/classes/XRNode3D.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="XRNode3D" inherits="Node3D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- A spatial node that has its position automatically updated by the [XRServer].
+ A 3D node that has its position automatically updated by the [XRServer].
</brief_description>
<description>
This node can be bound to a specific pose of a [XRPositionalTracker] and will automatically have its [member Node3D.transform] updated by the [XRServer]. Nodes of this type must be added as children of the [XROrigin3D] node.
diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py
index e1a6aa4a98..38e3edef2f 100755
--- a/doc/tools/make_rst.py
+++ b/doc/tools/make_rst.py
@@ -1555,9 +1555,7 @@ def make_enum(t: str, is_bitfield: bool, state: State) -> str:
else:
return f":ref:`{e}<enum_{c}_{e}>`"
- # Don't fail for `Vector3.Axis`, as this enum is a special case which is expected not to be resolved.
- if f"{c}.{e}" != "Vector3.Axis":
- print_error(f'{state.current_class}.xml: Unresolved enum "{t}".', state)
+ print_error(f'{state.current_class}.xml: Unresolved enum "{t}".', state)
return t
diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp
index 0c9635339b..6ee22b6eb5 100644
--- a/drivers/alsa/audio_driver_alsa.cpp
+++ b/drivers/alsa/audio_driver_alsa.cpp
@@ -80,7 +80,7 @@ Error AudioDriverALSA::init_output_device() {
status = snd_pcm_open(&pcm_handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
} else {
String device = output_device_name;
- int pos = device.find(";");
+ int pos = device.find_char(';');
if (pos != -1) {
device = device.substr(0, pos);
}
diff --git a/drivers/d3d12/rendering_context_driver_d3d12.cpp b/drivers/d3d12/rendering_context_driver_d3d12.cpp
index 8fa495f5c4..7cd36f90d2 100644
--- a/drivers/d3d12/rendering_context_driver_d3d12.cpp
+++ b/drivers/d3d12/rendering_context_driver_d3d12.cpp
@@ -96,6 +96,9 @@ RenderingContextDriverD3D12::~RenderingContextDriverD3D12() {
if (lib_dxgi) {
FreeLibrary(lib_dxgi);
}
+ if (lib_dcomp) {
+ FreeLibrary(lib_dcomp);
+ }
}
Error RenderingContextDriverD3D12::_init_device_factory() {
@@ -108,6 +111,9 @@ Error RenderingContextDriverD3D12::_init_device_factory() {
lib_dxgi = LoadLibraryW(L"DXGI.dll");
ERR_FAIL_NULL_V(lib_dxgi, ERR_CANT_CREATE);
+ lib_dcomp = LoadLibraryW(L"Dcomp.dll");
+ ERR_FAIL_NULL_V(lib_dcomp, ERR_CANT_CREATE);
+
// Note: symbol is not available in MinGW import library.
PFN_D3D12_GET_INTERFACE d3d_D3D12GetInterface = (PFN_D3D12_GET_INTERFACE)(void *)GetProcAddress(lib_d3d12, "D3D12GetInterface");
if (!d3d_D3D12GetInterface) {
diff --git a/drivers/d3d12/rendering_context_driver_d3d12.h b/drivers/d3d12/rendering_context_driver_d3d12.h
index a2d828ded1..3eed644481 100644
--- a/drivers/d3d12/rendering_context_driver_d3d12.h
+++ b/drivers/d3d12/rendering_context_driver_d3d12.h
@@ -59,6 +59,20 @@
#undef AS
#endif
+#if (WINVER < _WIN32_WINNT_WIN8) && defined(_MSC_VER)
+#pragma push_macro("NTDDI_VERSION")
+#pragma push_macro("WINVER")
+#undef NTDDI_VERSION
+#undef WINVER
+#define NTDDI_VERSION NTDDI_WIN8
+#define WINVER _WIN32_WINNT_WIN8
+#include <dcomp.h>
+#pragma pop_macro("WINVER")
+#pragma pop_macro("NTDDI_VERSION")
+#else
+#include <dcomp.h>
+#endif
+
#include "d3dx12.h"
#include <dxgi1_6.h>
@@ -114,10 +128,14 @@ public:
uint32_t height = 0;
DisplayServer::VSyncMode vsync_mode = DisplayServer::VSYNC_ENABLED;
bool needs_resize = false;
+ ComPtr<IDCompositionDevice> composition_device;
+ ComPtr<IDCompositionTarget> composition_target;
+ ComPtr<IDCompositionVisual> composition_visual;
};
HMODULE lib_d3d12 = nullptr;
HMODULE lib_dxgi = nullptr;
+ HMODULE lib_dcomp = nullptr;
IDXGIAdapter1 *create_adapter(uint32_t p_adapter_index) const;
ID3D12DeviceFactory *device_factory_get() const;
diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp
index 0cc89dfaca..b72a1932f8 100644
--- a/drivers/d3d12/rendering_device_driver_d3d12.cpp
+++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp
@@ -2160,6 +2160,7 @@ RDD::FenceID RenderingDeviceDriverD3D12::fence_create() {
Error RenderingDeviceDriverD3D12::fence_wait(FenceID p_fence) {
FenceInfo *fence = (FenceInfo *)(p_fence.id);
+ fence->d3d_fence->SetEventOnCompletion(fence->fence_value, fence->event_handle);
DWORD res = WaitForSingleObjectEx(fence->event_handle, INFINITE, FALSE);
#ifdef PIX_ENABLED
PIXNotifyWakeFromFenceSignal(fence->event_handle);
@@ -2254,7 +2255,6 @@ Error RenderingDeviceDriverD3D12::command_queue_execute_and_present(CommandQueue
FenceInfo *fence = (FenceInfo *)(p_cmd_fence.id);
fence->fence_value++;
command_queue->d3d_queue->Signal(fence->d3d_fence.Get(), fence->fence_value);
- fence->d3d_fence->SetEventOnCompletion(fence->fence_value, fence->event_handle);
}
}
@@ -2469,7 +2469,7 @@ Error RenderingDeviceDriverD3D12::swap_chain_resize(CommandQueueID p_cmd_queue,
DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {};
if (swap_chain->d3d_swap_chain != nullptr) {
_swap_chain_release_buffers(swap_chain);
- res = swap_chain->d3d_swap_chain->ResizeBuffers(p_desired_framebuffer_count, 0, 0, DXGI_FORMAT_UNKNOWN, creation_flags);
+ res = swap_chain->d3d_swap_chain->ResizeBuffers(p_desired_framebuffer_count, surface->width, surface->height, DXGI_FORMAT_UNKNOWN, creation_flags);
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_UNAVAILABLE);
} else {
swap_chain_desc.BufferCount = p_desired_framebuffer_count;
@@ -2478,7 +2478,7 @@ Error RenderingDeviceDriverD3D12::swap_chain_resize(CommandQueueID p_cmd_queue,
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swap_chain_desc.SampleDesc.Count = 1;
swap_chain_desc.Flags = creation_flags;
- swap_chain_desc.Scaling = DXGI_SCALING_NONE;
+ swap_chain_desc.Scaling = DXGI_SCALING_STRETCH;
if (OS::get_singleton()->is_layered_allowed()) {
swap_chain_desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
has_comp_alpha[(uint64_t)p_cmd_queue.id] = true;
@@ -2486,14 +2486,11 @@ Error RenderingDeviceDriverD3D12::swap_chain_resize(CommandQueueID p_cmd_queue,
swap_chain_desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
has_comp_alpha[(uint64_t)p_cmd_queue.id] = false;
}
+ swap_chain_desc.Width = surface->width;
+ swap_chain_desc.Height = surface->height;
ComPtr<IDXGISwapChain1> swap_chain_1;
- res = context_driver->dxgi_factory_get()->CreateSwapChainForHwnd(command_queue->d3d_queue.Get(), surface->hwnd, &swap_chain_desc, nullptr, nullptr, swap_chain_1.GetAddressOf());
- if (!SUCCEEDED(res) && swap_chain_desc.AlphaMode != DXGI_ALPHA_MODE_IGNORE) {
- swap_chain_desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
- has_comp_alpha[(uint64_t)p_cmd_queue.id] = false;
- res = context_driver->dxgi_factory_get()->CreateSwapChainForHwnd(command_queue->d3d_queue.Get(), surface->hwnd, &swap_chain_desc, nullptr, nullptr, swap_chain_1.GetAddressOf());
- }
+ res = context_driver->dxgi_factory_get()->CreateSwapChainForComposition(command_queue->d3d_queue.Get(), &swap_chain_desc, nullptr, swap_chain_1.GetAddressOf());
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
swap_chain_1.As(&swap_chain->d3d_swap_chain);
@@ -2503,6 +2500,36 @@ Error RenderingDeviceDriverD3D12::swap_chain_resize(CommandQueueID p_cmd_queue,
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
}
+ if (surface->composition_device.Get() == nullptr) {
+ using PFN_DCompositionCreateDevice = HRESULT(WINAPI *)(IDXGIDevice *, REFIID, void **);
+ PFN_DCompositionCreateDevice pfn_DCompositionCreateDevice = (PFN_DCompositionCreateDevice)(void *)GetProcAddress(context_driver->lib_dcomp, "DCompositionCreateDevice");
+ ERR_FAIL_NULL_V(pfn_DCompositionCreateDevice, ERR_CANT_CREATE);
+
+ res = pfn_DCompositionCreateDevice(nullptr, IID_PPV_ARGS(surface->composition_device.GetAddressOf()));
+ ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
+
+ res = surface->composition_device->CreateTargetForHwnd(surface->hwnd, TRUE, surface->composition_target.GetAddressOf());
+ ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
+
+ res = surface->composition_device->CreateVisual(surface->composition_visual.GetAddressOf());
+ ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
+
+ res = surface->composition_visual->SetContent(swap_chain->d3d_swap_chain.Get());
+ ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
+
+ res = surface->composition_target->SetRoot(surface->composition_visual.Get());
+ ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
+
+ res = surface->composition_device->Commit();
+ ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
+ } else {
+ res = surface->composition_visual->SetContent(swap_chain->d3d_swap_chain.Get());
+ ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
+
+ res = surface->composition_device->Commit();
+ ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
+ }
+
res = swap_chain->d3d_swap_chain->GetDesc1(&swap_chain_desc);
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
ERR_FAIL_COND_V(swap_chain_desc.BufferCount == 0, ERR_CANT_CREATE);
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 0138f99d50..5fd90744a4 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -687,6 +687,8 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
state.current_tex = RID();
+ const uint64_t base_specialization = GLES3::Config::get_singleton()->float_texture_supported ? 0 : CanvasShaderGLES3::USE_RGBA_SHADOWS;
+
for (uint32_t i = 0; i <= state.current_batch_index; i++) {
// Skipping when there is no instances.
if (state.canvas_instance_batches[i].instance_count == 0) {
@@ -705,10 +707,9 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
}
GLES3::CanvasMaterialData *material_data = state.canvas_instance_batches[i].material_data;
- CanvasShaderGLES3::ShaderVariant variant = state.canvas_instance_batches[i].shader_variant;
- uint64_t specialization = 0;
- specialization |= uint64_t(state.canvas_instance_batches[i].lights_disabled);
- specialization |= uint64_t(!GLES3::Config::get_singleton()->float_texture_supported) << 1;
+ CanvasShaderGLES3::ShaderVariant variant = CanvasShaderGLES3::MODE_DEFAULT;
+ uint64_t specialization = state.canvas_instance_batches[i].specialization;
+ specialization |= base_specialization;
RID shader_version = data.canvas_shader_default_version;
if (material_data) {
@@ -719,11 +720,14 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
}
}
- bool success = GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(shader_version, variant, specialization);
+ bool success = material_storage->shaders.canvas_shader.version_bind_shader(shader_version, variant, specialization);
if (!success) {
continue;
}
+ // Bind per-batch uniforms.
+ material_storage->shaders.canvas_shader.version_set_uniform(CanvasShaderGLES3::BATCH_FLAGS, state.canvas_instance_batches[i].flags, shader_version, variant, specialization);
+
GLES3::CanvasShaderData::BlendMode blend_mode = state.canvas_instance_batches[i].blend_mode;
Color blend_color = state.canvas_instance_batches[i].blend_color;
@@ -810,6 +814,7 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_render_target, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, GLES3::CanvasShaderData::BlendMode p_blend_mode, Light *p_lights, uint32_t &r_index, bool &r_batch_broken, bool &r_sdf_used, const Point2 &p_repeat_offset) {
RenderingServer::CanvasItemTextureFilter texture_filter = p_item->texture_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT ? state.default_filter : p_item->texture_filter;
+ const uint64_t specialization_command_mask = ~(CanvasShaderGLES3::USE_NINEPATCH | CanvasShaderGLES3::USE_PRIMITIVE | CanvasShaderGLES3::USE_ATTRIBUTES | CanvasShaderGLES3::USE_INSTANCING);
if (texture_filter != state.canvas_instance_batches[state.current_batch_index].filter) {
_new_batch(r_batch_broken);
@@ -845,6 +850,7 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
uint32_t lights[4] = { 0, 0, 0, 0 };
uint16_t light_count = 0;
+ uint16_t shadow_mask = 0;
{
Light *light = p_lights;
@@ -854,6 +860,10 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
uint32_t light_index = light->render_index_cache;
lights[light_count >> 2] |= light_index << ((light_count & 3) * 8);
+ if (p_item->light_mask & light->item_shadow_mask) {
+ shadow_mask |= 1 << light_count;
+ }
+
light_count++;
if (light_count == data.max_lights_per_item - 1) {
@@ -863,14 +873,15 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
light = light->next_ptr;
}
- base_flags |= light_count << FLAGS_LIGHT_COUNT_SHIFT;
+ base_flags |= light_count << INSTANCE_FLAGS_LIGHT_COUNT_SHIFT;
+ base_flags |= shadow_mask << INSTANCE_FLAGS_SHADOW_MASKED_SHIFT;
}
bool lights_disabled = light_count == 0 && !state.using_directional_lights;
- if (lights_disabled != state.canvas_instance_batches[state.current_batch_index].lights_disabled) {
+ if (lights_disabled != bool(state.canvas_instance_batches[state.current_batch_index].specialization & CanvasShaderGLES3::DISABLE_LIGHTING)) {
_new_batch(r_batch_broken);
- state.canvas_instance_batches[state.current_batch_index].lights_disabled = lights_disabled;
+ state.canvas_instance_batches[state.current_batch_index].specialization ^= CanvasShaderGLES3::DISABLE_LIGHTING;
}
const Item::Command *c = p_item->commands;
@@ -904,7 +915,7 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
state.instance_data_array[r_index].lights[2] = lights[2];
state.instance_data_array[r_index].lights[3] = lights[3];
- state.instance_data_array[r_index].flags = base_flags | (state.instance_data_array[r_index == 0 ? 0 : r_index - 1].flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); // Reset on each command for safety, keep canvastexture binding config.
+ state.instance_data_array[r_index].flags = base_flags;
Color blend_color = base_color;
GLES3::CanvasShaderData::BlendMode blend_mode = p_blend_mode;
@@ -936,7 +947,8 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
state.canvas_instance_batches[state.current_batch_index].tex = rect->texture;
state.canvas_instance_batches[state.current_batch_index].command_type = Item::Command::TYPE_RECT;
state.canvas_instance_batches[state.current_batch_index].command = c;
- state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_QUAD;
+ state.canvas_instance_batches[state.current_batch_index].specialization &= specialization_command_mask;
+ state.canvas_instance_batches[state.current_batch_index].flags = 0;
}
_prepare_canvas_texture(rect->texture, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
@@ -959,20 +971,18 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
if (rect->flags & CANVAS_RECT_FLIP_H) {
src_rect.size.x *= -1;
- state.instance_data_array[r_index].flags |= FLAGS_FLIP_H;
}
if (rect->flags & CANVAS_RECT_FLIP_V) {
src_rect.size.y *= -1;
- state.instance_data_array[r_index].flags |= FLAGS_FLIP_V;
}
if (rect->flags & CANVAS_RECT_TRANSPOSE) {
- state.instance_data_array[r_index].flags |= FLAGS_TRANSPOSE_RECT;
+ state.instance_data_array[r_index].flags |= INSTANCE_FLAGS_TRANSPOSE_RECT;
}
if (rect->flags & CANVAS_RECT_CLIP_UV) {
- state.instance_data_array[r_index].flags |= FLAGS_CLIP_RECT_UV;
+ state.instance_data_array[r_index].flags |= INSTANCE_FLAGS_CLIP_RECT_UV;
}
} else {
@@ -991,13 +1001,13 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
}
if (rect->flags & CANVAS_RECT_MSDF) {
- state.instance_data_array[r_index].flags |= FLAGS_USE_MSDF;
+ state.instance_data_array[r_index].flags |= INSTANCE_FLAGS_USE_MSDF;
state.instance_data_array[r_index].msdf[0] = rect->px_range; // Pixel range.
state.instance_data_array[r_index].msdf[1] = rect->outline; // Outline size.
state.instance_data_array[r_index].msdf[2] = 0.f; // Reserved.
state.instance_data_array[r_index].msdf[3] = 0.f; // Reserved.
} else if (rect->flags & CANVAS_RECT_LCD) {
- state.instance_data_array[r_index].flags |= FLAGS_USE_LCD;
+ state.instance_data_array[r_index].flags |= INSTANCE_FLAGS_USE_LCD;
}
state.instance_data_array[r_index].modulation[0] = rect->modulate.r * base_color.r;
@@ -1026,7 +1036,9 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
state.canvas_instance_batches[state.current_batch_index].tex = np->texture;
state.canvas_instance_batches[state.current_batch_index].command_type = Item::Command::TYPE_NINEPATCH;
state.canvas_instance_batches[state.current_batch_index].command = c;
- state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_NINEPATCH;
+ state.canvas_instance_batches[state.current_batch_index].specialization &= specialization_command_mask;
+ state.canvas_instance_batches[state.current_batch_index].specialization |= CanvasShaderGLES3::USE_NINEPATCH;
+ state.canvas_instance_batches[state.current_batch_index].flags = 0;
}
_prepare_canvas_texture(np->texture, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
@@ -1064,11 +1076,11 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
state.instance_data_array[r_index].dst_rect[2] = dst_rect.size.width;
state.instance_data_array[r_index].dst_rect[3] = dst_rect.size.height;
- state.instance_data_array[r_index].flags |= int(np->axis_x) << FLAGS_NINEPATCH_H_MODE_SHIFT;
- state.instance_data_array[r_index].flags |= int(np->axis_y) << FLAGS_NINEPATCH_V_MODE_SHIFT;
+ state.instance_data_array[r_index].flags |= int(np->axis_x) << INSTANCE_FLAGS_NINEPATCH_H_MODE_SHIFT;
+ state.instance_data_array[r_index].flags |= int(np->axis_y) << INSTANCE_FLAGS_NINEPATCH_V_MODE_SHIFT;
if (np->draw_center) {
- state.instance_data_array[r_index].flags |= FLAGS_NINEPACH_DRAW_CENTER;
+ state.instance_data_array[r_index].flags |= INSTANCE_FLAGS_NINEPACH_DRAW_CENTER;
}
state.instance_data_array[r_index].ninepatch_margins[0] = np->margin[SIDE_LEFT];
@@ -1092,7 +1104,9 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
state.canvas_instance_batches[state.current_batch_index].tex = polygon->texture;
state.canvas_instance_batches[state.current_batch_index].command_type = Item::Command::TYPE_POLYGON;
state.canvas_instance_batches[state.current_batch_index].command = c;
- state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_ATTRIBUTES;
+ state.canvas_instance_batches[state.current_batch_index].specialization &= specialization_command_mask;
+ state.canvas_instance_batches[state.current_batch_index].specialization |= CanvasShaderGLES3::USE_ATTRIBUTES;
+ state.canvas_instance_batches[state.current_batch_index].flags = 0;
_prepare_canvas_texture(polygon->texture, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
@@ -1119,7 +1133,9 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
state.canvas_instance_batches[state.current_batch_index].primitive_points = primitive->point_count;
state.canvas_instance_batches[state.current_batch_index].command_type = Item::Command::TYPE_PRIMITIVE;
state.canvas_instance_batches[state.current_batch_index].command = c;
- state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_PRIMITIVE;
+ state.canvas_instance_batches[state.current_batch_index].specialization &= specialization_command_mask;
+ state.canvas_instance_batches[state.current_batch_index].specialization |= CanvasShaderGLES3::USE_PRIMITIVE;
+ state.canvas_instance_batches[state.current_batch_index].flags = 0;
}
_prepare_canvas_texture(state.canvas_instance_batches[state.current_batch_index].tex, state.canvas_instance_batches[state.current_batch_index].filter, state.canvas_instance_batches[state.current_batch_index].repeat, r_index, texpixel_size);
@@ -1160,11 +1176,13 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
case Item::Command::TYPE_MESH:
case Item::Command::TYPE_MULTIMESH:
case Item::Command::TYPE_PARTICLES: {
- // Mesh's can't be batched, so always create a new batch
+ // Meshes can't be batched, so always create a new batch.
_new_batch(r_batch_broken);
Color modulate(1, 1, 1, 1);
- state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_ATTRIBUTES;
+ state.canvas_instance_batches[state.current_batch_index].specialization &= specialization_command_mask;
+ state.canvas_instance_batches[state.current_batch_index].specialization |= CanvasShaderGLES3::USE_ATTRIBUTES;
+ state.canvas_instance_batches[state.current_batch_index].flags = 0;
if (c->type == Item::Command::TYPE_MESH) {
const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c);
state.canvas_instance_batches[state.current_batch_index].tex = m->texture;
@@ -1174,13 +1192,13 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
} else if (c->type == Item::Command::TYPE_MULTIMESH) {
const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(c);
state.canvas_instance_batches[state.current_batch_index].tex = mm->texture;
- state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_INSTANCED;
+ state.canvas_instance_batches[state.current_batch_index].specialization |= CanvasShaderGLES3::USE_INSTANCING;
if (GLES3::MeshStorage::get_singleton()->multimesh_uses_colors(mm->multimesh)) {
- state.instance_data_array[r_index].flags |= FLAGS_INSTANCING_HAS_COLORS;
+ state.canvas_instance_batches[state.current_batch_index].flags |= BATCH_FLAGS_INSTANCING_HAS_COLORS;
}
if (GLES3::MeshStorage::get_singleton()->multimesh_uses_custom_data(mm->multimesh)) {
- state.instance_data_array[r_index].flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;
+ state.canvas_instance_batches[state.current_batch_index].flags |= BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA;
}
} else if (c->type == Item::Command::TYPE_PARTICLES) {
GLES3::ParticlesStorage *particles_storage = GLES3::ParticlesStorage::get_singleton();
@@ -1189,9 +1207,9 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(c);
RID particles = pt->particles;
state.canvas_instance_batches[state.current_batch_index].tex = pt->texture;
- state.canvas_instance_batches[state.current_batch_index].shader_variant = CanvasShaderGLES3::MODE_INSTANCED;
- state.instance_data_array[r_index].flags |= FLAGS_INSTANCING_HAS_COLORS;
- state.instance_data_array[r_index].flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;
+ state.canvas_instance_batches[state.current_batch_index].specialization |= CanvasShaderGLES3::USE_INSTANCING;
+ state.canvas_instance_batches[state.current_batch_index].flags |= BATCH_FLAGS_INSTANCING_HAS_COLORS;
+ state.canvas_instance_batches[state.current_batch_index].flags |= BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA;
if (particles_storage->particles_has_collision(particles) && texture_storage->render_target_is_sdf_enabled(p_render_target)) {
// Pass collision information.
@@ -2358,15 +2376,15 @@ void RasterizerCanvasGLES3::_prepare_canvas_texture(RID p_texture, RS::CanvasIte
GLES3::Texture *normal_map = texture_storage->get_texture(ct->normal_map);
if (ct->specular_color.a < 0.999) {
- state.instance_data_array[r_index].flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
+ state.canvas_instance_batches[state.current_batch_index].flags |= BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED;
} else {
- state.instance_data_array[r_index].flags &= ~FLAGS_DEFAULT_SPECULAR_MAP_USED;
+ state.canvas_instance_batches[state.current_batch_index].flags &= ~BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED;
}
if (normal_map) {
- state.instance_data_array[r_index].flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;
+ state.canvas_instance_batches[state.current_batch_index].flags |= BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED;
} else {
- state.instance_data_array[r_index].flags &= ~FLAGS_DEFAULT_NORMAL_MAP_USED;
+ state.canvas_instance_batches[state.current_batch_index].flags &= ~BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED;
}
state.instance_data_array[r_index].specular_shininess = uint32_t(CLAMP(ct->specular_color.a * 255.0, 0, 255)) << 24;
diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h
index a82e2713e0..e099fd0cc0 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.h
+++ b/drivers/gles3/rasterizer_canvas_gles3.h
@@ -54,29 +54,27 @@ class RasterizerCanvasGLES3 : public RendererCanvasRender {
_FORCE_INLINE_ void _update_transform_to_mat4(const Transform3D &p_transform, float *p_mat4);
enum {
+ INSTANCE_FLAGS_LIGHT_COUNT_SHIFT = 0, // 4 bits for light count.
- FLAGS_INSTANCING_MASK = 0x7F,
- FLAGS_INSTANCING_HAS_COLORS = (1 << 7),
- FLAGS_INSTANCING_HAS_CUSTOM_DATA = (1 << 8),
+ INSTANCE_FLAGS_CLIP_RECT_UV = (1 << 4),
+ INSTANCE_FLAGS_TRANSPOSE_RECT = (1 << 5),
+ INSTANCE_FLAGS_USE_MSDF = (1 << 6),
+ INSTANCE_FLAGS_USE_LCD = (1 << 7),
- FLAGS_CLIP_RECT_UV = (1 << 9),
- FLAGS_TRANSPOSE_RECT = (1 << 10),
+ INSTANCE_FLAGS_NINEPACH_DRAW_CENTER = (1 << 8),
+ INSTANCE_FLAGS_NINEPATCH_H_MODE_SHIFT = 9,
+ INSTANCE_FLAGS_NINEPATCH_V_MODE_SHIFT = 11,
- FLAGS_NINEPACH_DRAW_CENTER = (1 << 12),
-
- FLAGS_USE_SKELETON = (1 << 15),
- FLAGS_NINEPATCH_H_MODE_SHIFT = 16,
- FLAGS_NINEPATCH_V_MODE_SHIFT = 18,
- FLAGS_LIGHT_COUNT_SHIFT = 20,
-
- FLAGS_DEFAULT_NORMAL_MAP_USED = (1 << 26),
- FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 27),
+ INSTANCE_FLAGS_SHADOW_MASKED_SHIFT = 13, // 16 bits.
+ };
- FLAGS_USE_MSDF = (1 << 28),
- FLAGS_USE_LCD = (1 << 29),
+ enum {
+ BATCH_FLAGS_INSTANCING_MASK = 0x7F,
+ BATCH_FLAGS_INSTANCING_HAS_COLORS = (1 << 7),
+ BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA = (1 << 8),
- FLAGS_FLIP_H = (1 << 30),
- FLAGS_FLIP_V = (1 << 31),
+ BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED = (1 << 9),
+ BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 10),
};
enum {
@@ -273,14 +271,14 @@ public:
RID material;
GLES3::CanvasMaterialData *material_data = nullptr;
- CanvasShaderGLES3::ShaderVariant shader_variant = CanvasShaderGLES3::MODE_QUAD;
uint64_t vertex_input_mask = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_COLOR | RS::ARRAY_FORMAT_TEX_UV;
+ uint64_t specialization = 0;
const Item::Command *command = nullptr;
Item::Command::Type command_type = Item::Command::TYPE_ANIMATION_SLICE; // Can default to any type that doesn't form a batch.
uint32_t primitive_points = 0;
- bool lights_disabled = false;
+ uint32_t flags = 0;
};
// DataBuffer contains our per-frame data. I.e. the resources that are updated each frame.
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 537076d4ed..dfc7d02ac0 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -238,7 +238,7 @@ void RasterizerSceneGLES3::_geometry_instance_add_surface_with_material(Geometry
GLES3::SceneMaterialData *material_shadow = nullptr;
void *surface_shadow = nullptr;
- if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip && !p_material->shader_data->uses_world_coordinates) {
+ if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_prepass_alpha && !p_material->shader_data->uses_alpha_clip && !p_material->shader_data->uses_world_coordinates && !p_material->shader_data->wireframe) {
flags |= GeometryInstanceSurface::FLAG_USES_SHARED_SHADOW_MATERIAL;
material_shadow = static_cast<GLES3::SceneMaterialData *>(GLES3::MaterialStorage::get_singleton()->material_get_data(scene_globals.default_material, RS::SHADER_SPATIAL));
@@ -3157,7 +3157,7 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
}
bool use_wireframe = false;
- if (p_params->force_wireframe) {
+ if (p_params->force_wireframe || shader->wireframe) {
GLuint wireframe_index_array_gl = mesh_storage->mesh_surface_get_index_buffer_wireframe(mesh_surface);
if (wireframe_index_array_gl) {
index_array_gl = wireframe_index_array_gl;
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index 5e7fb3b338..3857aa8841 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -1,17 +1,16 @@
/* clang-format off */
#[modes]
-mode_quad =
-mode_ninepatch = #define USE_NINEPATCH
-mode_primitive = #define USE_PRIMITIVE
-mode_attributes = #define USE_ATTRIBUTES
-mode_instanced = #define USE_ATTRIBUTES \n#define USE_INSTANCING
+mode_default =
#[specializations]
DISABLE_LIGHTING = true
USE_RGBA_SHADOWS = false
-SINGLE_INSTANCE = false
+USE_NINEPATCH = false
+USE_PRIMITIVE = false
+USE_ATTRIBUTES = false
+USE_INSTANCING = false
#[vertex]
@@ -111,6 +110,9 @@ layout(std140) uniform MaterialUniforms{ //ubo:4
};
#endif
+
+uniform mediump uint batch_flags;
+
/* clang-format on */
#include "canvas_uniforms_inc.glsl"
@@ -180,13 +182,13 @@ void main() {
vec2 uv = uv_attrib;
#ifdef USE_INSTANCING
- if (bool(read_draw_data_flags & FLAGS_INSTANCING_HAS_COLORS)) {
+ if (bool(batch_flags & BATCH_FLAGS_INSTANCING_HAS_COLORS)) {
vec4 instance_color;
instance_color.xy = unpackHalf2x16(uint(instance_color_custom_data.x));
instance_color.zw = unpackHalf2x16(uint(instance_color_custom_data.y));
color *= instance_color;
}
- if (bool(read_draw_data_flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
+ if (bool(batch_flags & BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
instance_custom.xy = unpackHalf2x16(instance_color_custom_data.z);
instance_custom.zw = unpackHalf2x16(instance_color_custom_data.w);
}
@@ -219,7 +221,7 @@ void main() {
else if (vertex_id == 5)
vertex_base = vec2(1.0, 1.0);
- vec2 uv = read_draw_data_src_rect.xy + abs(read_draw_data_src_rect.zw) * ((read_draw_data_flags & FLAGS_TRANSPOSE_RECT) != uint(0) ? vertex_base.yx : vertex_base.xy);
+ vec2 uv = read_draw_data_src_rect.xy + abs(read_draw_data_src_rect.zw) * ((read_draw_data_flags & INSTANCE_FLAGS_TRANSPOSE_RECT) != uint(0) ? vertex_base.yx : vertex_base.xy);
vec4 color = read_draw_data_modulation;
vec2 vertex = read_draw_data_dst_rect.xy + abs(read_draw_data_dst_rect.zw) * mix(vertex_base, vec2(1.0, 1.0) - vertex_base, lessThan(read_draw_data_src_rect.zw, vec2(0.0, 0.0)));
@@ -337,6 +339,8 @@ uniform sampler2D specular_texture; //texunit:-7
uniform sampler2D color_texture; //texunit:0
+uniform mediump uint batch_flags;
+
layout(location = 0) out vec4 frag_color;
/* clang-format off */
@@ -520,7 +524,7 @@ float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, flo
} else if (pixel >= draw_size - margin_end) {
return (tex_size - (draw_size - pixel)) * tex_pixel_size;
} else {
- if (!bool(read_draw_data_flags & FLAGS_NINEPACH_DRAW_CENTER)) {
+ if (!bool(read_draw_data_flags & INSTANCE_FLAGS_NINEPATCH_DRAW_CENTER)) {
draw_center--;
}
@@ -568,8 +572,8 @@ void main() {
int draw_center = 2;
uv = vec2(
- map_ninepatch_axis(pixel_size_interp.x, abs(read_draw_data_dst_rect_z), read_draw_data_color_texture_pixel_size.x, read_draw_data_ninepatch_margins.x, read_draw_data_ninepatch_margins.z, int(read_draw_data_flags >> FLAGS_NINEPATCH_H_MODE_SHIFT) & 0x3, draw_center),
- map_ninepatch_axis(pixel_size_interp.y, abs(read_draw_data_dst_rect_w), read_draw_data_color_texture_pixel_size.y, read_draw_data_ninepatch_margins.y, read_draw_data_ninepatch_margins.w, int(read_draw_data_flags >> FLAGS_NINEPATCH_V_MODE_SHIFT) & 0x3, draw_center));
+ map_ninepatch_axis(pixel_size_interp.x, abs(read_draw_data_dst_rect_z), read_draw_data_color_texture_pixel_size.x, read_draw_data_ninepatch_margins.x, read_draw_data_ninepatch_margins.z, int(read_draw_data_flags >> INSTANCE_FLAGS_NINEPATCH_H_MODE_SHIFT) & 0x3, draw_center),
+ map_ninepatch_axis(pixel_size_interp.y, abs(read_draw_data_dst_rect_w), read_draw_data_color_texture_pixel_size.y, read_draw_data_ninepatch_margins.y, read_draw_data_ninepatch_margins.w, int(read_draw_data_flags >> INSTANCE_FLAGS_NINEPATCH_V_MODE_SHIFT) & 0x3, draw_center));
if (draw_center == 0) {
color.a = 0.0;
@@ -578,7 +582,7 @@ void main() {
uv = uv * read_draw_data_src_rect.zw + read_draw_data_src_rect.xy; //apply region if needed
#endif
- if (bool(read_draw_data_flags & FLAGS_CLIP_RECT_UV)) {
+ if (bool(read_draw_data_flags & INSTANCE_FLAGS_CLIP_RECT_UV)) {
vec2 half_texpixel = read_draw_data_color_texture_pixel_size * 0.5;
uv = clamp(uv, read_draw_data_src_rect.xy + half_texpixel, read_draw_data_src_rect.xy + abs(read_draw_data_src_rect.zw) - half_texpixel);
}
@@ -586,7 +590,7 @@ void main() {
#endif
#ifndef USE_PRIMITIVE
- if (bool(read_draw_data_flags & FLAGS_USE_MSDF)) {
+ if (bool(read_draw_data_flags & INSTANCE_FLAGS_USE_MSDF)) {
float px_range = read_draw_data_ninepatch_margins.x;
float outline_thickness = read_draw_data_ninepatch_margins.y;
@@ -604,7 +608,7 @@ void main() {
float a = clamp(d * px_size + 0.5, 0.0, 1.0);
color.a = a * color.a;
}
- } else if (bool(read_draw_data_flags & FLAGS_USE_LCD)) {
+ } else if (bool(read_draw_data_flags & INSTANCE_FLAGS_USE_LCD)) {
vec4 lcd_sample = texture(color_texture, uv);
if (lcd_sample.a == 1.0) {
color.rgb = lcd_sample.rgb * color.a;
@@ -618,7 +622,7 @@ void main() {
color *= texture(color_texture, uv);
}
- uint light_count = (read_draw_data_flags >> uint(FLAGS_LIGHT_COUNT_SHIFT)) & uint(0xF); //max 16 lights
+ uint light_count = read_draw_data_flags & uint(0xF); // Max 16 lights.
bool using_light = light_count > 0u || directional_light_count > 0u;
vec3 normal;
@@ -629,17 +633,16 @@ void main() {
bool normal_used = false;
#endif
- if (normal_used || (using_light && bool(read_draw_data_flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
+ if (normal_used || (using_light && bool(batch_flags & BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED))) {
normal.xy = texture(normal_texture, uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0);
- if (bool(read_draw_data_flags & FLAGS_TRANSPOSE_RECT)) {
+
+#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
+ if (bool(read_draw_data_flags & INSTANCE_FLAGS_TRANSPOSE_RECT)) {
normal.xy = normal.yx;
}
- if (bool(read_draw_data_flags & FLAGS_FLIP_H)) {
- normal.x = -normal.x;
- }
- if (bool(read_draw_data_flags & FLAGS_FLIP_V)) {
- normal.y = -normal.y;
- }
+ normal.xy *= sign(read_draw_data_src_rect.zw);
+#endif
+
normal.z = sqrt(max(0.0, 1.0 - dot(normal.xy, normal.xy)));
normal_used = true;
} else {
@@ -655,7 +658,7 @@ void main() {
bool specular_shininess_used = false;
#endif
- if (specular_shininess_used || (using_light && normal_used && bool(read_draw_data_flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
+ if (specular_shininess_used || (using_light && normal_used && bool(batch_flags & BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
specular_shininess = texture(specular_texture, uv);
specular_shininess *= godot_unpackUnorm4x8(read_draw_data_specular_shininess);
specular_shininess_used = true;
@@ -728,7 +731,7 @@ void main() {
}
#endif
- if (bool(light_array[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
+ if (bool(light_array[light_base].flags & LIGHT_FLAGS_HAS_SHADOW) && bool(read_draw_data_flags & uint(INSTANCE_FLAGS_SHADOW_MASKED << i))) {
vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array[light_base].shadow_matrix[0], light_array[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
vec4 shadow_uv = vec4(shadow_pos.x, light_array[light_base].shadow_y_ofs, shadow_pos.y * light_array[light_base].shadow_zfar_inv, 1.0);
@@ -803,7 +806,7 @@ void main() {
}
#endif
- if (bool(light_array[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
+ if (bool(light_array[light_base].flags & LIGHT_FLAGS_HAS_SHADOW) && bool(read_draw_data_flags & uint(INSTANCE_FLAGS_SHADOW_MASKED << i))) {
vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array[light_base].shadow_matrix[0], light_array[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
vec2 pos_norm = normalize(shadow_pos);
diff --git a/drivers/gles3/shaders/canvas_uniforms_inc.glsl b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
index f6ad2b730a..94cbbdd8a7 100644
--- a/drivers/gles3/shaders/canvas_uniforms_inc.glsl
+++ b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
@@ -1,33 +1,32 @@
-
#define MAX_LIGHTS_PER_ITEM uint(16)
#define M_PI 3.14159265359
#define SDF_MAX_LENGTH 16384.0
-//1 means enabled, 2+ means trails in use
-#define FLAGS_INSTANCING_MASK uint(0x7F)
-#define FLAGS_INSTANCING_HAS_COLORS uint(1 << 7)
-#define FLAGS_INSTANCING_HAS_CUSTOM_DATA uint(1 << 8)
-
-#define FLAGS_CLIP_RECT_UV uint(1 << 9)
-#define FLAGS_TRANSPOSE_RECT uint(1 << 10)
-// (1 << 11) is for FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR in RD backends, unused here.
-#define FLAGS_NINEPACH_DRAW_CENTER uint(1 << 12)
+#define INSTANCE_FLAGS_LIGHT_COUNT_SHIFT 0 // 4 bits.
-#define FLAGS_NINEPATCH_H_MODE_SHIFT 16
-#define FLAGS_NINEPATCH_V_MODE_SHIFT 18
+#define INSTANCE_FLAGS_CLIP_RECT_UV uint(1 << 4)
+#define INSTANCE_FLAGS_TRANSPOSE_RECT uint(1 << 5)
+#define INSTANCE_FLAGS_USE_MSDF uint(1 << 6)
+#define INSTANCE_FLAGS_USE_LCD uint(1 << 7)
-#define FLAGS_LIGHT_COUNT_SHIFT 20
+#define INSTANCE_FLAGS_NINEPATCH_DRAW_CENTER uint(1 << 8)
+#define INSTANCE_FLAGS_NINEPATCH_H_MODE_SHIFT 9
+#define INSTANCE_FLAGS_NINEPATCH_V_MODE_SHIFT 11
-#define FLAGS_DEFAULT_NORMAL_MAP_USED uint(1 << 26)
-#define FLAGS_DEFAULT_SPECULAR_MAP_USED uint(1 << 27)
+#define INSTANCE_FLAGS_SHADOW_MASKED_SHIFT 13u // 16 bits.
+#define INSTANCE_FLAGS_SHADOW_MASKED uint(1 << INSTANCE_FLAGS_SHADOW_MASKED_SHIFT)
-#define FLAGS_USE_MSDF uint(1 << 28)
-#define FLAGS_USE_LCD uint(1 << 29)
+// 1 means enabled, 2+ means trails in use
+#define BATCH_FLAGS_INSTANCING_MASK uint(0x7F)
+#define BATCH_FLAGS_INSTANCING_HAS_COLORS_SHIFT 7
+#define BATCH_FLAGS_INSTANCING_HAS_COLORS uint(1 << BATCH_FLAGS_INSTANCING_HAS_COLORS_SHIFT)
+#define BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA_SHIFT 8
+#define BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA uint(1 << BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA_SHIFT)
-#define FLAGS_FLIP_H uint(1 << 30)
-#define FLAGS_FLIP_V uint(1 << 31)
+#define BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED uint(1 << 9)
+#define BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED uint(1 << 10)
layout(std140) uniform GlobalShaderUniformData { //ubo:1
vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index fcfbeddb9e..2022c8ee43 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -1259,7 +1259,7 @@ float SchlickFresnel(float u) {
return m2 * m2 * m; // pow(m,5)
}
-void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_directional, float attenuation, vec3 f0, float roughness, float metallic, float specular_amount, vec3 albedo, inout float alpha,
+void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_directional, float attenuation, vec3 f0, float roughness, float metallic, float specular_amount, vec3 albedo, inout float alpha, vec2 screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
@@ -1423,7 +1423,7 @@ float get_omni_spot_attenuation(float distance, float inv_range, float decay) {
}
#if !defined(DISABLE_LIGHT_OMNI) || defined(ADDITIVE_OMNI)
-void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha,
+void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha, vec2 screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
@@ -1450,7 +1450,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
omni_attenuation *= shadow;
- light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, omni_attenuation, f0, roughness, metallic, omni_lights[idx].specular_amount, albedo, alpha,
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, omni_attenuation, f0, roughness, metallic, omni_lights[idx].specular_amount, albedo, alpha, screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -1469,7 +1469,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
#endif // !DISABLE_LIGHT_OMNI
#if !defined(DISABLE_LIGHT_SPOT) || defined(ADDITIVE_SPOT)
-void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha,
+void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, float roughness, float metallic, float shadow, vec3 albedo, inout float alpha, vec2 screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
@@ -1506,7 +1506,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
spot_attenuation *= shadow;
- light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, spot_attenuation, f0, roughness, metallic, spot_lights[idx].specular_amount, albedo, alpha,
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, spot_attenuation, f0, roughness, metallic, spot_lights[idx].specular_amount, albedo, alpha, screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -2114,7 +2114,7 @@ void main() {
continue;
}
#endif
- light_compute(normal, normalize(directional_lights[i].direction), normalize(view), directional_lights[i].size, directional_lights[i].color * directional_lights[i].energy, true, 1.0, f0, roughness, metallic, 1.0, albedo, alpha,
+ light_compute(normal, normalize(directional_lights[i].direction), normalize(view), directional_lights[i].size, directional_lights[i].color * directional_lights[i].energy, true, 1.0, f0, roughness, metallic, 1.0, albedo, alpha, screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -2143,7 +2143,7 @@ void main() {
continue;
}
#endif
- light_process_omni(omni_light_indices[i], vertex, view, normal, f0, roughness, metallic, 1.0, albedo, alpha,
+ light_process_omni(omni_light_indices[i], vertex, view, normal, f0, roughness, metallic, 1.0, albedo, alpha, screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -2171,7 +2171,7 @@ void main() {
continue;
}
#endif
- light_process_spot(spot_light_indices[i], vertex, view, normal, f0, roughness, metallic, 1.0, albedo, alpha,
+ light_process_spot(spot_light_indices[i], vertex, view, normal, f0, roughness, metallic, 1.0, albedo, alpha, screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -2389,7 +2389,7 @@ void main() {
#endif // SHADOWS_DISABLED
#ifndef USE_VERTEX_LIGHTING
- light_compute(normal, normalize(directional_lights[directional_shadow_index].direction), normalize(view), directional_lights[directional_shadow_index].size, directional_lights[directional_shadow_index].color * directional_lights[directional_shadow_index].energy, true, directional_shadow, f0, roughness, metallic, 1.0, albedo, alpha,
+ light_compute(normal, normalize(directional_lights[directional_shadow_index].direction), normalize(view), directional_lights[directional_shadow_index].size, directional_lights[directional_shadow_index].color * directional_lights[directional_shadow_index].energy, true, directional_shadow, f0, roughness, metallic, 1.0, albedo, alpha, screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -2421,7 +2421,7 @@ void main() {
#endif // SHADOWS_DISABLED
#ifndef USE_VERTEX_LIGHTING
- light_process_omni(omni_light_index, vertex, view, normal, f0, roughness, metallic, omni_shadow, albedo, alpha,
+ light_process_omni(omni_light_index, vertex, view, normal, f0, roughness, metallic, omni_shadow, albedo, alpha, screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -2451,7 +2451,7 @@ void main() {
#endif // SHADOWS_DISABLED
#ifndef USE_VERTEX_LIGHTING
- light_process_spot(spot_light_index, vertex, view, normal, f0, roughness, metallic, spot_shadow, albedo, alpha,
+ light_process_spot(spot_light_index, vertex, view, normal, f0, roughness, metallic, spot_shadow, albedo, alpha, screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
diff --git a/drivers/gles3/shaders/sky.glsl b/drivers/gles3/shaders/sky.glsl
index 186b630bc8..043023aee0 100644
--- a/drivers/gles3/shaders/sky.glsl
+++ b/drivers/gles3/shaders/sky.glsl
@@ -2,17 +2,15 @@
#[modes]
mode_background =
-mode_half_res = #define USE_HALF_RES_PASS
-mode_quarter_res = #define USE_QUARTER_RES_PASS
mode_cubemap = #define USE_CUBEMAP_PASS
-mode_cubemap_half_res = #define USE_CUBEMAP_PASS \n#define USE_HALF_RES_PASS
-mode_cubemap_quarter_res = #define USE_CUBEMAP_PASS \n#define USE_QUARTER_RES_PASS
#[specializations]
USE_MULTIVIEW = false
USE_INVERTED_Y = true
APPLY_TONEMAPPING = true
+USE_QUARTER_RES_PASS = false
+USE_HALF_RES_PASS = false
#[vertex]
diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp
index 73d95d75ba..630bfdf1b7 100644
--- a/drivers/gles3/storage/mesh_storage.cpp
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -1974,6 +1974,10 @@ void MeshStorage::_multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_
}
}
+RID MeshStorage::_multimesh_get_buffer_rd_rid(RID p_multimesh) const {
+ ERR_FAIL_V_MSG(RID(), "GLES3 does not contain a Rid for the multimesh buffer.");
+}
+
Vector<float> MeshStorage::_multimesh_get_buffer(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, Vector<float>());
diff --git a/drivers/gles3/storage/mesh_storage.h b/drivers/gles3/storage/mesh_storage.h
index 0bb20bd369..5e3a56366e 100644
--- a/drivers/gles3/storage/mesh_storage.h
+++ b/drivers/gles3/storage/mesh_storage.h
@@ -517,6 +517,7 @@ public:
virtual Color _multimesh_instance_get_color(RID p_multimesh, int p_index) const override;
virtual Color _multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override;
virtual void _multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override;
+ virtual RID _multimesh_get_buffer_rd_rid(RID p_multimesh) const override;
virtual Vector<float> _multimesh_get_buffer(RID p_multimesh) const override;
virtual void _multimesh_set_visible_instances(RID p_multimesh, int p_visible) override;
diff --git a/drivers/metal/rendering_context_driver_metal.h b/drivers/metal/rendering_context_driver_metal.h
index 7e0b09186d..1fdc255f93 100644
--- a/drivers/metal/rendering_context_driver_metal.h
+++ b/drivers/metal/rendering_context_driver_metal.h
@@ -107,6 +107,7 @@ public:
uint32_t height = 0;
DisplayServer::VSyncMode vsync_mode = DisplayServer::VSYNC_ENABLED;
bool needs_resize = false;
+ double present_minimum_duration = 0.0;
Surface(
#ifdef __OBJC__
@@ -123,6 +124,7 @@ public:
virtual Error resize(uint32_t p_desired_framebuffer_count) = 0;
virtual RDD::FramebufferID acquire_next_frame_buffer() = 0;
virtual void present(MDCommandBuffer *p_cmd_buffer) = 0;
+ void set_max_fps(int p_max_fps) { present_minimum_duration = p_max_fps ? 1.0 / p_max_fps : 0.0; }
};
#ifdef __OBJC__
diff --git a/drivers/metal/rendering_context_driver_metal.mm b/drivers/metal/rendering_context_driver_metal.mm
index cf8c7e1c83..199ec25d79 100644
--- a/drivers/metal/rendering_context_driver_metal.mm
+++ b/drivers/metal/rendering_context_driver_metal.mm
@@ -172,7 +172,7 @@ public:
count--;
front = (front + 1) % frame_buffers.size();
- [p_cmd_buffer->get_command_buffer() presentDrawable:drawable];
+ [p_cmd_buffer->get_command_buffer() presentDrawable:drawable afterMinimumDuration:present_minimum_duration];
}
};
diff --git a/drivers/metal/rendering_device_driver_metal.h b/drivers/metal/rendering_device_driver_metal.h
index e238de958e..09ab7601e9 100644
--- a/drivers/metal/rendering_device_driver_metal.h
+++ b/drivers/metal/rendering_device_driver_metal.h
@@ -220,6 +220,7 @@ public:
virtual FramebufferID swap_chain_acquire_framebuffer(CommandQueueID p_cmd_queue, SwapChainID p_swap_chain, bool &r_resize_required) override final;
virtual RenderPassID swap_chain_get_render_pass(SwapChainID p_swap_chain) override final;
virtual DataFormat swap_chain_get_format(SwapChainID p_swap_chain) override final;
+ virtual void swap_chain_set_max_fps(SwapChainID p_swap_chain, int p_max_fps) override final;
virtual void swap_chain_free(SwapChainID p_swap_chain) override final;
#pragma mark - Frame Buffer
diff --git a/drivers/metal/rendering_device_driver_metal.mm b/drivers/metal/rendering_device_driver_metal.mm
index d90f528a14..784c9d5ae8 100644
--- a/drivers/metal/rendering_device_driver_metal.mm
+++ b/drivers/metal/rendering_device_driver_metal.mm
@@ -982,6 +982,12 @@ RDD::DataFormat RenderingDeviceDriverMetal::swap_chain_get_format(SwapChainID p_
return swap_chain->data_format;
}
+void RenderingDeviceDriverMetal::swap_chain_set_max_fps(SwapChainID p_swap_chain, int p_max_fps) {
+ SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id);
+ RenderingContextDriverMetal::Surface *metal_surface = (RenderingContextDriverMetal::Surface *)(swap_chain->surface);
+ metal_surface->set_max_fps(p_max_fps);
+}
+
void RenderingDeviceDriverMetal::swap_chain_free(SwapChainID p_swap_chain) {
SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id);
_swap_chain_release(swap_chain);
@@ -1026,7 +1032,7 @@ void RenderingDeviceDriverMetal::framebuffer_free(FramebufferID p_framebuffer) {
#pragma mark - Shader
-const uint32_t SHADER_BINARY_VERSION = 2;
+const uint32_t SHADER_BINARY_VERSION = 3;
// region Serialization
@@ -1330,23 +1336,32 @@ struct ComputeSize {
struct ShaderStageData {
RD::ShaderStage stage = RD::ShaderStage::SHADER_STAGE_MAX;
+ uint32_t is_position_invariant = UINT32_MAX;
+ uint32_t supports_fast_math = UINT32_MAX;
CharString entry_point_name;
CharString source;
size_t serialize_size() const {
int comp_size = Compression::get_max_compressed_buffer_size(source.length(), Compression::MODE_ZSTD);
return sizeof(uint32_t) // Stage.
- + sizeof(uint32_t) /* entry_point_name.utf8().length */ + entry_point_name.length() + sizeof(uint32_t) /* uncompressed size */ + sizeof(uint32_t) /* compressed size */ + comp_size;
+ + sizeof(uint32_t) // is_position_invariant
+ + sizeof(uint32_t) // supports_fast_math
+ + sizeof(uint32_t) /* entry_point_name.utf8().length */
+ + entry_point_name.length() + sizeof(uint32_t) /* uncompressed size */ + sizeof(uint32_t) /* compressed size */ + comp_size;
}
void serialize(BufWriter &p_writer) const {
p_writer.write((uint32_t)stage);
+ p_writer.write(is_position_invariant);
+ p_writer.write(supports_fast_math);
p_writer.write(entry_point_name);
p_writer.write_compressed(source);
}
void deserialize(BufReader &p_reader) {
p_reader.read((uint32_t &)stage);
+ p_reader.read(is_position_invariant);
+ p_reader.read(supports_fast_math);
p_reader.read(entry_point_name);
p_reader.read_compressed(source);
}
@@ -2005,7 +2020,8 @@ Vector<uint8_t> RenderingDeviceDriverMetal::shader_compile_binary_from_spirv(Vec
ERR_FAIL_COND_V_MSG(compiler.get_entry_points_and_stages().size() != 1, Result(), "Expected a single entry point and stage.");
- EntryPoint &entry_point_stage = compiler.get_entry_points_and_stages().front();
+ SmallVector<EntryPoint> entry_pts_stages = compiler.get_entry_points_and_stages();
+ EntryPoint &entry_point_stage = entry_pts_stages.front();
SPIREntryPoint &entry_point = compiler.get_entry_point(entry_point_stage.name, entry_point_stage.execution_model);
// Process specialization constants.
@@ -2287,6 +2303,8 @@ Vector<uint8_t> RenderingDeviceDriverMetal::shader_compile_binary_from_spirv(Vec
ShaderStageData stage_data;
stage_data.stage = v.shader_stage;
+ stage_data.is_position_invariant = compiler.is_position_invariant();
+ stage_data.supports_fast_math = !entry_point.flags.get(spv::ExecutionModeSignedZeroInfNanPreserve);
stage_data.entry_point_name = entry_point.name.c_str();
stage_data.source = source.c_str();
bin_data.stages.push_back(stage_data);
@@ -2359,7 +2377,8 @@ RDD::ShaderID RenderingDeviceDriverMetal::shader_create_from_bytecode(const Vect
ShaderCacheEntry *cd = memnew(ShaderCacheEntry(*this, key));
cd->name = binary_data.shader_name;
cd->stage = shader_data.stage;
-
+ options.preserveInvariance = shader_data.is_position_invariant;
+ options.fastMathEnabled = YES;
MDLibrary *library = [MDLibrary newLibraryWithCacheEntry:cd
device:device
source:source
diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp
index 43ad0799ba..4b92e5f8a1 100644
--- a/drivers/unix/file_access_unix.cpp
+++ b/drivers/unix/file_access_unix.cpp
@@ -118,7 +118,7 @@ Error FileAccessUnix::open_internal(const String &p_path, int p_mode_flags) {
last_error = ERR_FILE_CANT_OPEN;
return last_error;
}
- fchmod(fd, 0666);
+ fchmod(fd, 0644);
path = String::utf8(cs.ptr());
f = fdopen(fd, mode_string);
diff --git a/drivers/unix/file_access_unix_pipe.cpp b/drivers/unix/file_access_unix_pipe.cpp
index 0a78429dec..fd60bec9d0 100644
--- a/drivers/unix/file_access_unix_pipe.cpp
+++ b/drivers/unix/file_access_unix_pipe.cpp
@@ -70,7 +70,7 @@ Error FileAccessUnixPipe::open_internal(const String &p_path, int p_mode_flags)
struct stat st = {};
int err = stat(path.utf8().get_data(), &st);
if (err) {
- if (mkfifo(path.utf8().get_data(), 0666) != 0) {
+ if (mkfifo(path.utf8().get_data(), 0600) != 0) {
last_error = ERR_FILE_CANT_OPEN;
return last_error;
}
diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp
index 5987c1675d..5a1a26e874 100644
--- a/drivers/unix/ip_unix.cpp
+++ b/drivers/unix/ip_unix.cpp
@@ -28,22 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#include "ip_unix.h"
-
-#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED)
-
-#ifdef WINDOWS_ENABLED
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <winsock2.h>
-#include <ws2tcpip.h>
-
-#include <iphlpapi.h>
-
-#include <stdio.h>
+#if defined(UNIX_ENABLED)
-#else // UNIX
+#include "ip_unix.h"
#include <netdb.h>
@@ -67,8 +54,6 @@
#include <net/if.h> // Order is important on OpenBSD, leave as last.
-#endif // UNIX
-
#include <string.h>
static IPAddress _sockaddr2ip(struct sockaddr *p_addr) {
@@ -108,7 +93,7 @@ void IPUnix::_resolve_hostname(List<IPAddress> &r_addresses, const String &p_hos
}
if (result == nullptr || result->ai_addr == nullptr) {
- print_verbose("Invalid response from getaddrinfo");
+ print_verbose("Invalid response from getaddrinfo.");
if (result) {
freeaddrinfo(result);
}
@@ -132,56 +117,6 @@ void IPUnix::_resolve_hostname(List<IPAddress> &r_addresses, const String &p_hos
freeaddrinfo(result);
}
-#if defined(WINDOWS_ENABLED)
-
-void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const {
- ULONG buf_size = 1024;
- IP_ADAPTER_ADDRESSES *addrs;
-
- while (true) {
- addrs = (IP_ADAPTER_ADDRESSES *)memalloc(buf_size);
- int err = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME,
- nullptr, addrs, &buf_size);
- if (err == NO_ERROR) {
- break;
- }
- memfree(addrs);
- if (err == ERROR_BUFFER_OVERFLOW) {
- continue; // will go back and alloc the right size
- }
-
- ERR_FAIL_MSG("Call to GetAdaptersAddresses failed with error " + itos(err) + ".");
- }
-
- IP_ADAPTER_ADDRESSES *adapter = addrs;
-
- while (adapter != nullptr) {
- Interface_Info info;
- info.name = adapter->AdapterName;
- info.name_friendly = adapter->FriendlyName;
- info.index = String::num_uint64(adapter->IfIndex);
-
- IP_ADAPTER_UNICAST_ADDRESS *address = adapter->FirstUnicastAddress;
- while (address != nullptr) {
- int family = address->Address.lpSockaddr->sa_family;
- if (family != AF_INET && family != AF_INET6) {
- continue;
- }
- info.ip_addresses.push_front(_sockaddr2ip(address->Address.lpSockaddr));
- address = address->Next;
- }
- adapter = adapter->Next;
- // Only add interface if it has at least one IP
- if (info.ip_addresses.size() > 0) {
- r_interfaces->insert(info.name, info);
- }
- }
-
- memfree(addrs);
-}
-
-#else // UNIX
-
void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const {
struct ifaddrs *ifAddrStruct = nullptr;
struct ifaddrs *ifa = nullptr;
@@ -219,8 +154,6 @@ void IPUnix::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces)
}
}
-#endif // UNIX
-
void IPUnix::make_default() {
_create = _create_unix;
}
@@ -232,4 +165,4 @@ IP *IPUnix::_create_unix() {
IPUnix::IPUnix() {
}
-#endif // UNIX_ENABLED || WINDOWS_ENABLED
+#endif // UNIX_ENABLED
diff --git a/drivers/unix/ip_unix.h b/drivers/unix/ip_unix.h
index 274b7c561e..7e496629ef 100644
--- a/drivers/unix/ip_unix.h
+++ b/drivers/unix/ip_unix.h
@@ -31,9 +31,9 @@
#ifndef IP_UNIX_H
#define IP_UNIX_H
-#include "core/io/ip.h"
+#if defined(UNIX_ENABLED)
-#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED)
+#include "core/io/ip.h"
class IPUnix : public IP {
GDCLASS(IPUnix, IP);
@@ -49,6 +49,6 @@ public:
IPUnix();
};
-#endif
+#endif // UNIX_ENABLED
#endif // IP_UNIX_H
diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_unix.cpp
index 5caa33100e..3eaf1b2885 100644
--- a/drivers/unix/net_socket_posix.cpp
+++ b/drivers/unix/net_socket_unix.cpp
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* net_socket_posix.cpp */
+/* net_socket_unix.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,13 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#include "net_socket_posix.h"
-
// Some proprietary Unix-derived platforms don't expose Unix sockets
// so this allows skipping this file to reimplement this API differently.
-#ifndef UNIX_SOCKET_UNAVAILABLE
+#if defined(UNIX_ENABLED) && !defined(UNIX_SOCKET_UNAVAILABLE)
-#if defined(UNIX_ENABLED)
+#include "net_socket_unix.h"
#include <errno.h>
#include <fcntl.h>
@@ -62,44 +60,11 @@
#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
#endif
-// Some custom defines to minimize ifdefs
-#define SOCK_EMPTY -1
-#define SOCK_BUF(x) x
-#define SOCK_CBUF(x) x
-#define SOCK_IOCTL ioctl
-#define SOCK_FIONREAD_LEN_TYPE int
-#define SOCK_CLOSE ::close
-#define SOCK_CONNECT(p_sock, p_addr, p_addr_len) ::connect(p_sock, p_addr, p_addr_len)
-
-/* Windows */
-#elif defined(WINDOWS_ENABLED)
-#include <winsock2.h>
-#include <ws2tcpip.h>
-
-#include <mswsock.h>
-// Some custom defines to minimize ifdefs
-#define SOCK_EMPTY INVALID_SOCKET
-#define SOCK_BUF(x) (char *)(x)
-#define SOCK_CBUF(x) (const char *)(x)
-#define SOCK_IOCTL ioctlsocket
-#define SOCK_FIONREAD_LEN_TYPE unsigned long
-#define SOCK_CLOSE closesocket
-// connect is broken on windows under certain conditions, reasons unknown:
-// See https://github.com/godotengine/webrtc-native/issues/6
-#define SOCK_CONNECT(p_sock, p_addr, p_addr_len) ::WSAConnect(p_sock, p_addr, p_addr_len, nullptr, nullptr, nullptr, nullptr)
-
-// Workaround missing flag in MinGW
-#if defined(__MINGW32__) && !defined(SIO_UDP_NETRESET)
-#define SIO_UDP_NETRESET _WSAIOW(IOC_VENDOR, 15)
-#endif
-
-#endif // UNIX_ENABLED
-
-size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const IPAddress &p_ip, uint16_t p_port, IP::Type p_ip_type) {
+size_t NetSocketUnix::_set_addr_storage(struct sockaddr_storage *p_addr, const IPAddress &p_ip, uint16_t p_port, IP::Type p_ip_type) {
memset(p_addr, 0, sizeof(struct sockaddr_storage));
- if (p_ip_type == IP::TYPE_IPV6 || p_ip_type == IP::TYPE_ANY) { // IPv6 socket
+ if (p_ip_type == IP::TYPE_IPV6 || p_ip_type == IP::TYPE_ANY) { // IPv6 socket.
- // IPv6 only socket with IPv4 address
+ // IPv6 only socket with IPv4 address.
ERR_FAIL_COND_V(!p_ip.is_wildcard() && p_ip_type == IP::TYPE_IPV6 && p_ip.is_ipv4(), 0);
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr;
@@ -111,14 +76,14 @@ size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const
addr6->sin6_addr = in6addr_any;
}
return sizeof(sockaddr_in6);
- } else { // IPv4 socket
+ } else { // IPv4 socket.
- // IPv4 socket with IPv6 address
+ // IPv4 socket with IPv6 address.
ERR_FAIL_COND_V(!p_ip.is_wildcard() && !p_ip.is_ipv4(), 0);
struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr;
addr4->sin_family = AF_INET;
- addr4->sin_port = htons(p_port); // short, network byte order
+ addr4->sin_port = htons(p_port); // Short, network byte order.
if (p_ip.is_valid()) {
memcpy(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 4);
@@ -130,7 +95,7 @@ size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const
}
}
-void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_ip, uint16_t *r_port) {
+void NetSocketUnix::_set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_ip, uint16_t *r_port) {
if (p_addr->ss_family == AF_INET) {
struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr;
if (r_ip) {
@@ -150,34 +115,21 @@ void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_
}
}
-NetSocket *NetSocketPosix::_create_func() {
- return memnew(NetSocketPosix);
+NetSocket *NetSocketUnix::_create_func() {
+ return memnew(NetSocketUnix);
}
-void NetSocketPosix::make_default() {
-#if defined(WINDOWS_ENABLED)
- if (_create == nullptr) {
- WSADATA data;
- WSAStartup(MAKEWORD(2, 2), &data);
- }
-#endif
+void NetSocketUnix::make_default() {
_create = _create_func;
}
-void NetSocketPosix::cleanup() {
-#if defined(WINDOWS_ENABLED)
- if (_create != nullptr) {
- WSACleanup();
- }
- _create = nullptr;
-#endif
+void NetSocketUnix::cleanup() {
}
-NetSocketPosix::NetSocketPosix() :
- _sock(SOCK_EMPTY) {
+NetSocketUnix::NetSocketUnix() {
}
-NetSocketPosix::~NetSocketPosix() {
+NetSocketUnix::~NetSocketUnix() {
close();
}
@@ -188,30 +140,7 @@ NetSocketPosix::~NetSocketPosix() {
#pragma GCC diagnostic ignored "-Wlogical-op"
#endif
-NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const {
-#if defined(WINDOWS_ENABLED)
- int err = WSAGetLastError();
- if (err == WSAEISCONN) {
- return ERR_NET_IS_CONNECTED;
- }
- if (err == WSAEINPROGRESS || err == WSAEALREADY) {
- return ERR_NET_IN_PROGRESS;
- }
- if (err == WSAEWOULDBLOCK) {
- return ERR_NET_WOULD_BLOCK;
- }
- if (err == WSAEADDRINUSE || err == WSAEADDRNOTAVAIL) {
- return ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE;
- }
- if (err == WSAEACCES) {
- return ERR_NET_UNAUTHORIZED;
- }
- if (err == WSAEMSGSIZE || err == WSAENOBUFS) {
- return ERR_NET_BUFFER_TOO_SMALL;
- }
- print_verbose("Socket error: " + itos(err));
- return ERR_NET_OTHER;
-#else
+NetSocketUnix::NetError NetSocketUnix::_get_socket_error() const {
if (errno == EISCONN) {
return ERR_NET_IS_CONNECTED;
}
@@ -230,16 +159,15 @@ NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const {
if (errno == ENOBUFS) {
return ERR_NET_BUFFER_TOO_SMALL;
}
- print_verbose("Socket error: " + itos(errno));
+ print_verbose("Socket error: " + itos(errno) + ".");
return ERR_NET_OTHER;
-#endif
}
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
-bool NetSocketPosix::_can_use_ip(const IPAddress &p_ip, const bool p_for_bind) const {
+bool NetSocketUnix::_can_use_ip(const IPAddress &p_ip, const bool p_for_bind) const {
if (p_for_bind && !(p_ip.is_valid() || p_ip.is_wildcard())) {
return false;
} else if (!p_for_bind && !p_ip.is_valid()) {
@@ -250,11 +178,11 @@ bool NetSocketPosix::_can_use_ip(const IPAddress &p_ip, const bool p_for_bind) c
return !(_ip_type != IP::TYPE_ANY && !p_ip.is_wildcard() && _ip_type != type);
}
-_FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IPAddress p_ip, String p_if_name, bool p_add) {
+_FORCE_INLINE_ Error NetSocketUnix::_change_multicast_group(IPAddress p_ip, String p_if_name, bool p_add) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
ERR_FAIL_COND_V(!_can_use_ip(p_ip, false), ERR_INVALID_PARAMETER);
- // Need to force level and af_family to IP(v4) when using dual stacking and provided multicast group is IPv4
+ // Need to force level and af_family to IP(v4) when using dual stacking and provided multicast group is IPv4.
IP::Type type = _ip_type == IP::TYPE_ANY && p_ip.is_ipv4() ? IP::TYPE_IPV4 : _ip_type;
// This needs to be the proper level for the multicast group, no matter if the socket is dual stacking.
int level = type == IP::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
@@ -277,7 +205,7 @@ _FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IPAddress p_ip, Str
for (const IPAddress &F : c.ip_addresses) {
if (!F.is_ipv4()) {
- continue; // Wrong IP type
+ continue; // Wrong IP type.
}
if_ip = F;
break;
@@ -304,7 +232,7 @@ _FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IPAddress p_ip, Str
return OK;
}
-void NetSocketPosix::_set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream) {
+void NetSocketUnix::_set_socket(int p_sock, IP::Type p_ip_type, bool p_is_stream) {
_sock = p_sock;
_ip_type = p_ip_type;
_is_stream = p_is_stream;
@@ -312,15 +240,13 @@ void NetSocketPosix::_set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_
_set_close_exec_enabled(true);
}
-void NetSocketPosix::_set_close_exec_enabled(bool p_enabled) {
-#ifndef WINDOWS_ENABLED
+void NetSocketUnix::_set_close_exec_enabled(bool p_enabled) {
// Enable close on exec to avoid sharing with subprocesses. Off by default on Windows.
int opts = fcntl(_sock, F_GETFD);
fcntl(_sock, F_SETFD, opts | FD_CLOEXEC);
-#endif
}
-Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) {
+Error NetSocketUnix::open(Type p_sock_type, IP::Type &ip_type) {
ERR_FAIL_COND_V(is_open(), ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(ip_type > IP::TYPE_ANY || ip_type < IP::TYPE_NONE, ERR_INVALID_PARAMETER);
@@ -336,7 +262,7 @@ Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) {
int type = p_sock_type == TYPE_TCP ? SOCK_STREAM : SOCK_DGRAM;
_sock = socket(family, type, protocol);
- if (_sock == SOCK_EMPTY && ip_type == IP::TYPE_ANY) {
+ if (_sock == -1 && ip_type == IP::TYPE_ANY) {
// Careful here, changing the referenced parameter so the caller knows that we are using an IPv4 socket
// in place of a dual stack one, and further calls to _set_sock_addr will work as expected.
ip_type = IP::TYPE_IPV4;
@@ -344,11 +270,11 @@ Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) {
_sock = socket(family, type, protocol);
}
- ERR_FAIL_COND_V(_sock == SOCK_EMPTY, FAILED);
+ ERR_FAIL_COND_V(_sock == -1, FAILED);
_ip_type = ip_type;
if (family == AF_INET6) {
- // Select IPv4 over IPv6 mapping
+ // Select IPv4 over IPv6 mapping.
set_ipv6_only_enabled(ip_type != IP::TYPE_ANY);
}
@@ -363,41 +289,27 @@ Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) {
// Disable descriptor sharing with subprocesses.
_set_close_exec_enabled(true);
-#if defined(WINDOWS_ENABLED)
- if (!_is_stream) {
- // Disable windows feature/bug reporting WSAECONNRESET/WSAENETRESET when
- // recv/recvfrom and an ICMP reply was received from a previous send/sendto.
- unsigned long disable = 0;
- if (ioctlsocket(_sock, SIO_UDP_CONNRESET, &disable) == SOCKET_ERROR) {
- print_verbose("Unable to turn off UDP WSAECONNRESET behavior on Windows");
- }
- if (ioctlsocket(_sock, SIO_UDP_NETRESET, &disable) == SOCKET_ERROR) {
- // This feature seems not to be supported on wine.
- print_verbose("Unable to turn off UDP WSAENETRESET behavior on Windows");
- }
- }
-#endif
#if defined(SO_NOSIGPIPE)
- // Disable SIGPIPE (should only be relevant to stream sockets, but seems to affect UDP too on iOS)
+ // Disable SIGPIPE (should only be relevant to stream sockets, but seems to affect UDP too on iOS).
int par = 1;
- if (setsockopt(_sock, SOL_SOCKET, SO_NOSIGPIPE, SOCK_CBUF(&par), sizeof(int)) != 0) {
- print_verbose("Unable to turn off SIGPIPE on socket");
+ if (setsockopt(_sock, SOL_SOCKET, SO_NOSIGPIPE, &par, sizeof(int)) != 0) {
+ print_verbose("Unable to turn off SIGPIPE on socket.");
}
#endif
return OK;
}
-void NetSocketPosix::close() {
- if (_sock != SOCK_EMPTY) {
- SOCK_CLOSE(_sock);
+void NetSocketUnix::close() {
+ if (_sock != -1) {
+ ::close(_sock);
}
- _sock = SOCK_EMPTY;
+ _sock = -1;
_ip_type = IP::TYPE_NONE;
_is_stream = false;
}
-Error NetSocketPosix::bind(IPAddress p_addr, uint16_t p_port) {
+Error NetSocketUnix::bind(IPAddress p_addr, uint16_t p_port) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
ERR_FAIL_COND_V(!_can_use_ip(p_addr, true), ERR_INVALID_PARAMETER);
@@ -406,7 +318,7 @@ Error NetSocketPosix::bind(IPAddress p_addr, uint16_t p_port) {
if (::bind(_sock, (struct sockaddr *)&addr, addr_size) != 0) {
NetError err = _get_socket_error();
- print_verbose("Failed to bind socket. Error: " + itos(err));
+ print_verbose("Failed to bind socket. Error: " + itos(err) + ".");
close();
return ERR_UNAVAILABLE;
}
@@ -414,7 +326,7 @@ Error NetSocketPosix::bind(IPAddress p_addr, uint16_t p_port) {
return OK;
}
-Error NetSocketPosix::listen(int p_max_pending) {
+Error NetSocketUnix::listen(int p_max_pending) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
if (::listen(_sock, p_max_pending) != 0) {
@@ -427,26 +339,26 @@ Error NetSocketPosix::listen(int p_max_pending) {
return OK;
}
-Error NetSocketPosix::connect_to_host(IPAddress p_host, uint16_t p_port) {
+Error NetSocketUnix::connect_to_host(IPAddress p_host, uint16_t p_port) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
ERR_FAIL_COND_V(!_can_use_ip(p_host, false), ERR_INVALID_PARAMETER);
struct sockaddr_storage addr;
size_t addr_size = _set_addr_storage(&addr, p_host, p_port, _ip_type);
- if (SOCK_CONNECT(_sock, (struct sockaddr *)&addr, addr_size) != 0) {
+ if (::connect(_sock, (struct sockaddr *)&addr, addr_size) != 0) {
NetError err = _get_socket_error();
switch (err) {
- // We are already connected
+ // We are already connected.
case ERR_NET_IS_CONNECTED:
return OK;
- // Still waiting to connect, try again in a while
+ // Still waiting to connect, try again in a while.
case ERR_NET_WOULD_BLOCK:
case ERR_NET_IN_PROGRESS:
return ERR_BUSY;
default:
- print_verbose("Connection to remote host failed!");
+ print_verbose("Connection to remote host failed.");
close();
return FAILED;
}
@@ -455,66 +367,9 @@ Error NetSocketPosix::connect_to_host(IPAddress p_host, uint16_t p_port) {
return OK;
}
-Error NetSocketPosix::poll(PollType p_type, int p_timeout) const {
+Error NetSocketUnix::poll(PollType p_type, int p_timeout) const {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
-#if defined(WINDOWS_ENABLED)
- bool ready = false;
- fd_set rd, wr, ex;
- fd_set *rdp = nullptr;
- fd_set *wrp = nullptr;
- FD_ZERO(&rd);
- FD_ZERO(&wr);
- FD_ZERO(&ex);
- FD_SET(_sock, &ex);
- struct timeval timeout = { p_timeout / 1000, (p_timeout % 1000) * 1000 };
- // For blocking operation, pass nullptr timeout pointer to select.
- struct timeval *tp = nullptr;
- if (p_timeout >= 0) {
- // If timeout is non-negative, we want to specify the timeout instead.
- tp = &timeout;
- }
-
- switch (p_type) {
- case POLL_TYPE_IN:
- FD_SET(_sock, &rd);
- rdp = &rd;
- break;
- case POLL_TYPE_OUT:
- FD_SET(_sock, &wr);
- wrp = &wr;
- break;
- case POLL_TYPE_IN_OUT:
- FD_SET(_sock, &rd);
- FD_SET(_sock, &wr);
- rdp = &rd;
- wrp = &wr;
- }
- int ret = select(1, rdp, wrp, &ex, tp);
-
- if (ret == SOCKET_ERROR) {
- return FAILED;
- }
-
- if (ret == 0) {
- return ERR_BUSY;
- }
-
- if (FD_ISSET(_sock, &ex)) {
- _get_socket_error();
- print_verbose("Exception when polling socket.");
- return FAILED;
- }
-
- if (rdp && FD_ISSET(_sock, rdp)) {
- ready = true;
- }
- if (wrp && FD_ISSET(_sock, wrp)) {
- ready = true;
- }
-
- return ready ? OK : ERR_BUSY;
-#else
struct pollfd pfd;
pfd.fd = _sock;
pfd.events = POLLIN;
@@ -544,13 +399,12 @@ Error NetSocketPosix::poll(PollType p_type, int p_timeout) const {
}
return OK;
-#endif
}
-Error NetSocketPosix::recv(uint8_t *p_buffer, int p_len, int &r_read) {
+Error NetSocketUnix::recv(uint8_t *p_buffer, int p_len, int &r_read) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
- r_read = ::recv(_sock, SOCK_BUF(p_buffer), p_len, 0);
+ r_read = ::recv(_sock, p_buffer, p_len, 0);
if (r_read < 0) {
NetError err = _get_socket_error();
@@ -568,14 +422,14 @@ Error NetSocketPosix::recv(uint8_t *p_buffer, int p_len, int &r_read) {
return OK;
}
-Error NetSocketPosix::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek) {
+Error NetSocketUnix::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
struct sockaddr_storage from;
socklen_t len = sizeof(struct sockaddr_storage);
memset(&from, 0, len);
- r_read = ::recvfrom(_sock, SOCK_BUF(p_buffer), p_len, p_peek ? MSG_PEEK : 0, (struct sockaddr *)&from, &len);
+ r_read = ::recvfrom(_sock, p_buffer, p_len, p_peek ? MSG_PEEK : 0, (struct sockaddr *)&from, &len);
if (r_read < 0) {
NetError err = _get_socket_error();
@@ -606,7 +460,7 @@ Error NetSocketPosix::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddr
return OK;
}
-Error NetSocketPosix::send(const uint8_t *p_buffer, int p_len, int &r_sent) {
+Error NetSocketUnix::send(const uint8_t *p_buffer, int p_len, int &r_sent) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
int flags = 0;
@@ -615,7 +469,7 @@ Error NetSocketPosix::send(const uint8_t *p_buffer, int p_len, int &r_sent) {
flags = MSG_NOSIGNAL;
}
#endif
- r_sent = ::send(_sock, SOCK_CBUF(p_buffer), p_len, flags);
+ r_sent = ::send(_sock, p_buffer, p_len, flags);
if (r_sent < 0) {
NetError err = _get_socket_error();
@@ -632,12 +486,12 @@ Error NetSocketPosix::send(const uint8_t *p_buffer, int p_len, int &r_sent) {
return OK;
}
-Error NetSocketPosix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) {
+Error NetSocketUnix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
struct sockaddr_storage addr;
size_t addr_size = _set_addr_storage(&addr, p_ip, p_port, _ip_type);
- r_sent = ::sendto(_sock, SOCK_CBUF(p_buffer), p_len, 0, (struct sockaddr *)&addr, addr_size);
+ r_sent = ::sendto(_sock, p_buffer, p_len, 0, (struct sockaddr *)&addr, addr_size);
if (r_sent < 0) {
NetError err = _get_socket_error();
@@ -654,7 +508,7 @@ Error NetSocketPosix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP
return OK;
}
-Error NetSocketPosix::set_broadcasting_enabled(bool p_enabled) {
+Error NetSocketUnix::set_broadcasting_enabled(bool p_enabled) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
// IPv6 has no broadcast support.
if (_ip_type == IP::TYPE_IPV6) {
@@ -662,90 +516,68 @@ Error NetSocketPosix::set_broadcasting_enabled(bool p_enabled) {
}
int par = p_enabled ? 1 : 0;
- if (setsockopt(_sock, SOL_SOCKET, SO_BROADCAST, SOCK_CBUF(&par), sizeof(int)) != 0) {
- WARN_PRINT("Unable to change broadcast setting");
+ if (setsockopt(_sock, SOL_SOCKET, SO_BROADCAST, &par, sizeof(int)) != 0) {
+ WARN_PRINT("Unable to change broadcast setting.");
return FAILED;
}
return OK;
}
-void NetSocketPosix::set_blocking_enabled(bool p_enabled) {
+void NetSocketUnix::set_blocking_enabled(bool p_enabled) {
ERR_FAIL_COND(!is_open());
int ret = 0;
-#if defined(WINDOWS_ENABLED)
- unsigned long par = p_enabled ? 0 : 1;
- ret = SOCK_IOCTL(_sock, FIONBIO, &par);
-#else
int opts = fcntl(_sock, F_GETFL);
if (p_enabled) {
ret = fcntl(_sock, F_SETFL, opts & ~O_NONBLOCK);
} else {
ret = fcntl(_sock, F_SETFL, opts | O_NONBLOCK);
}
-#endif
if (ret != 0) {
- WARN_PRINT("Unable to change non-block mode");
+ WARN_PRINT("Unable to change non-block mode.");
}
}
-void NetSocketPosix::set_ipv6_only_enabled(bool p_enabled) {
+void NetSocketUnix::set_ipv6_only_enabled(bool p_enabled) {
ERR_FAIL_COND(!is_open());
// This option is only available in IPv6 sockets.
ERR_FAIL_COND(_ip_type == IP::TYPE_IPV4);
int par = p_enabled ? 1 : 0;
- if (setsockopt(_sock, IPPROTO_IPV6, IPV6_V6ONLY, SOCK_CBUF(&par), sizeof(int)) != 0) {
- WARN_PRINT("Unable to change IPv4 address mapping over IPv6 option");
+ if (setsockopt(_sock, IPPROTO_IPV6, IPV6_V6ONLY, &par, sizeof(int)) != 0) {
+ WARN_PRINT("Unable to change IPv4 address mapping over IPv6 option.");
}
}
-void NetSocketPosix::set_tcp_no_delay_enabled(bool p_enabled) {
+void NetSocketUnix::set_tcp_no_delay_enabled(bool p_enabled) {
ERR_FAIL_COND(!is_open());
- ERR_FAIL_COND(!_is_stream); // Not TCP
+ ERR_FAIL_COND(!_is_stream); // Not TCP.
int par = p_enabled ? 1 : 0;
- if (setsockopt(_sock, IPPROTO_TCP, TCP_NODELAY, SOCK_CBUF(&par), sizeof(int)) < 0) {
- ERR_PRINT("Unable to set TCP no delay option");
+ if (setsockopt(_sock, IPPROTO_TCP, TCP_NODELAY, &par, sizeof(int)) < 0) {
+ WARN_PRINT("Unable to set TCP no delay option.");
}
}
-void NetSocketPosix::set_reuse_address_enabled(bool p_enabled) {
+void NetSocketUnix::set_reuse_address_enabled(bool p_enabled) {
ERR_FAIL_COND(!is_open());
-// On Windows, enabling SO_REUSEADDR actually would also enable reuse port, very bad on TCP. Denying...
-// Windows does not have this option, SO_REUSEADDR in this magical world means SO_REUSEPORT
-#ifndef WINDOWS_ENABLED
- int par = p_enabled ? 1 : 0;
- if (setsockopt(_sock, SOL_SOCKET, SO_REUSEADDR, SOCK_CBUF(&par), sizeof(int)) < 0) {
- WARN_PRINT("Unable to set socket REUSEADDR option!");
- }
-#endif
-}
-
-void NetSocketPosix::set_reuse_port_enabled(bool p_enabled) {
- ERR_FAIL_COND(!is_open());
-
-// See comment above...
-#ifdef WINDOWS_ENABLED
-#define SO_REUSEPORT SO_REUSEADDR
-#endif
int par = p_enabled ? 1 : 0;
- if (setsockopt(_sock, SOL_SOCKET, SO_REUSEPORT, SOCK_CBUF(&par), sizeof(int)) < 0) {
- WARN_PRINT("Unable to set socket REUSEPORT option!");
+ if (setsockopt(_sock, SOL_SOCKET, SO_REUSEADDR, &par, sizeof(int)) < 0) {
+ WARN_PRINT("Unable to set socket REUSEADDR option.");
}
}
-bool NetSocketPosix::is_open() const {
- return _sock != SOCK_EMPTY;
+bool NetSocketUnix::is_open() const {
+ return _sock != -1;
}
-int NetSocketPosix::get_available_bytes() const {
+int NetSocketUnix::get_available_bytes() const {
ERR_FAIL_COND_V(!is_open(), -1);
- SOCK_FIONREAD_LEN_TYPE len;
- int ret = SOCK_IOCTL(_sock, FIONREAD, &len);
+ int len;
+ int ret = ioctl(_sock, FIONREAD, &len);
if (ret == -1) {
_get_socket_error();
print_verbose("Error when checking available bytes on socket.");
@@ -754,7 +586,7 @@ int NetSocketPosix::get_available_bytes() const {
return len;
}
-Error NetSocketPosix::get_socket_address(IPAddress *r_ip, uint16_t *r_port) const {
+Error NetSocketUnix::get_socket_address(IPAddress *r_ip, uint16_t *r_port) const {
ERR_FAIL_COND_V(!is_open(), FAILED);
struct sockaddr_storage saddr;
@@ -768,14 +600,14 @@ Error NetSocketPosix::get_socket_address(IPAddress *r_ip, uint16_t *r_port) cons
return OK;
}
-Ref<NetSocket> NetSocketPosix::accept(IPAddress &r_ip, uint16_t &r_port) {
+Ref<NetSocket> NetSocketUnix::accept(IPAddress &r_ip, uint16_t &r_port) {
Ref<NetSocket> out;
ERR_FAIL_COND_V(!is_open(), out);
struct sockaddr_storage their_addr;
socklen_t size = sizeof(their_addr);
- SOCKET_TYPE fd = ::accept(_sock, (struct sockaddr *)&their_addr, &size);
- if (fd == SOCK_EMPTY) {
+ int fd = ::accept(_sock, (struct sockaddr *)&their_addr, &size);
+ if (fd == -1) {
_get_socket_error();
print_verbose("Error when accepting socket connection.");
return out;
@@ -783,18 +615,18 @@ Ref<NetSocket> NetSocketPosix::accept(IPAddress &r_ip, uint16_t &r_port) {
_set_ip_port(&their_addr, &r_ip, &r_port);
- NetSocketPosix *ns = memnew(NetSocketPosix);
+ NetSocketUnix *ns = memnew(NetSocketUnix);
ns->_set_socket(fd, _ip_type, _is_stream);
ns->set_blocking_enabled(false);
return Ref<NetSocket>(ns);
}
-Error NetSocketPosix::join_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
+Error NetSocketUnix::join_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
return _change_multicast_group(p_multi_address, p_if_name, true);
}
-Error NetSocketPosix::leave_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
+Error NetSocketUnix::leave_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
return _change_multicast_group(p_multi_address, p_if_name, false);
}
-#endif // UNIX_SOCKET_UNAVAILABLE
+#endif // UNIX_ENABLED && !UNIX_SOCKET_UNAVAILABLE
diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_unix.h
index aa59ff36ee..08c45f2ac3 100644
--- a/drivers/unix/net_socket_posix.h
+++ b/drivers/unix/net_socket_unix.h
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* net_socket_posix.h */
+/* net_socket_unix.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,25 +28,18 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifndef NET_SOCKET_POSIX_H
-#define NET_SOCKET_POSIX_H
+#ifndef NET_SOCKET_UNIX_H
+#define NET_SOCKET_UNIX_H
-#include "core/io/net_socket.h"
+#if defined(UNIX_ENABLED) && !defined(UNIX_SOCKET_UNAVAILABLE)
-#if defined(WINDOWS_ENABLED)
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#define SOCKET_TYPE SOCKET
+#include "core/io/net_socket.h"
-#else
#include <sys/socket.h>
-#define SOCKET_TYPE int
-#endif
-
-class NetSocketPosix : public NetSocket {
+class NetSocketUnix : public NetSocket {
private:
- SOCKET_TYPE _sock; // NOLINT - the default value is defined in the .cpp
+ int _sock = -1;
IP::Type _ip_type = IP::TYPE_NONE;
bool _is_stream = false;
@@ -61,7 +54,7 @@ private:
};
NetError _get_socket_error() const;
- void _set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream);
+ void _set_socket(int p_sock, IP::Type p_ip_type, bool p_is_stream);
_FORCE_INLINE_ Error _change_multicast_group(IPAddress p_ip, String p_if_name, bool p_add);
_FORCE_INLINE_ void _set_close_exec_enabled(bool p_enabled);
@@ -76,33 +69,34 @@ public:
static void _set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_ip, uint16_t *r_port);
static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IPAddress &p_ip, uint16_t p_port, IP::Type p_ip_type);
- virtual Error open(Type p_sock_type, IP::Type &ip_type);
- virtual void close();
- virtual Error bind(IPAddress p_addr, uint16_t p_port);
- virtual Error listen(int p_max_pending);
- virtual Error connect_to_host(IPAddress p_host, uint16_t p_port);
- virtual Error poll(PollType p_type, int timeout) const;
- virtual Error recv(uint8_t *p_buffer, int p_len, int &r_read);
- virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek = false);
- virtual Error send(const uint8_t *p_buffer, int p_len, int &r_sent);
- virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port);
- virtual Ref<NetSocket> accept(IPAddress &r_ip, uint16_t &r_port);
-
- virtual bool is_open() const;
- virtual int get_available_bytes() const;
- virtual Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) const;
-
- virtual Error set_broadcasting_enabled(bool p_enabled);
- virtual void set_blocking_enabled(bool p_enabled);
- virtual void set_ipv6_only_enabled(bool p_enabled);
- virtual void set_tcp_no_delay_enabled(bool p_enabled);
- virtual void set_reuse_address_enabled(bool p_enabled);
- virtual void set_reuse_port_enabled(bool p_enabled);
- virtual Error join_multicast_group(const IPAddress &p_multi_address, const String &p_if_name);
- virtual Error leave_multicast_group(const IPAddress &p_multi_address, const String &p_if_name);
-
- NetSocketPosix();
- ~NetSocketPosix();
+ virtual Error open(Type p_sock_type, IP::Type &ip_type) override;
+ virtual void close() override;
+ virtual Error bind(IPAddress p_addr, uint16_t p_port) override;
+ virtual Error listen(int p_max_pending) override;
+ virtual Error connect_to_host(IPAddress p_host, uint16_t p_port) override;
+ virtual Error poll(PollType p_type, int timeout) const override;
+ virtual Error recv(uint8_t *p_buffer, int p_len, int &r_read) override;
+ virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek = false) override;
+ virtual Error send(const uint8_t *p_buffer, int p_len, int &r_sent) override;
+ virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) override;
+ virtual Ref<NetSocket> accept(IPAddress &r_ip, uint16_t &r_port) override;
+
+ virtual bool is_open() const override;
+ virtual int get_available_bytes() const override;
+ virtual Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) const override;
+
+ virtual Error set_broadcasting_enabled(bool p_enabled) override;
+ virtual void set_blocking_enabled(bool p_enabled) override;
+ virtual void set_ipv6_only_enabled(bool p_enabled) override;
+ virtual void set_tcp_no_delay_enabled(bool p_enabled) override;
+ virtual void set_reuse_address_enabled(bool p_enabled) override;
+ virtual Error join_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) override;
+ virtual Error leave_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) override;
+
+ NetSocketUnix();
+ ~NetSocketUnix() override;
};
-#endif // NET_SOCKET_POSIX_H
+#endif // UNIX_ENABLED && !UNIX_SOCKET_UNAVAILABLE
+
+#endif // NET_SOCKET_UNIX_H
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index 8a9b130068..299ac6536f 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -38,7 +38,7 @@
#include "drivers/unix/dir_access_unix.h"
#include "drivers/unix/file_access_unix.h"
#include "drivers/unix/file_access_unix_pipe.h"
-#include "drivers/unix/net_socket_posix.h"
+#include "drivers/unix/net_socket_unix.h"
#include "drivers/unix/thread_posix.h"
#include "servers/rendering_server.h"
@@ -77,6 +77,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
+#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <time.h>
@@ -166,7 +167,9 @@ void OS_Unix::initialize_core() {
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA);
DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM);
- NetSocketPosix::make_default();
+#ifndef UNIX_SOCKET_UNAVAILABLE
+ NetSocketUnix::make_default();
+#endif
IPUnix::make_default();
process_map = memnew((HashMap<ProcessID, ProcessInfo>));
@@ -175,16 +178,96 @@ void OS_Unix::initialize_core() {
void OS_Unix::finalize_core() {
memdelete(process_map);
- NetSocketPosix::cleanup();
+#ifndef UNIX_SOCKET_UNAVAILABLE
+ NetSocketUnix::cleanup();
+#endif
}
Vector<String> OS_Unix::get_video_adapter_driver_info() const {
return Vector<String>();
}
-String OS_Unix::get_stdin_string() {
- char buff[1024];
- return String::utf8(fgets(buff, 1024, stdin));
+String OS_Unix::get_stdin_string(int64_t p_buffer_size) {
+ Vector<uint8_t> data;
+ data.resize(p_buffer_size);
+ if (fgets((char *)data.ptrw(), data.size(), stdin)) {
+ return String::utf8((char *)data.ptr()).replace("\r\n", "\n").rstrip("\n");
+ }
+ return String();
+}
+
+PackedByteArray OS_Unix::get_stdin_buffer(int64_t p_buffer_size) {
+ Vector<uint8_t> data;
+ data.resize(p_buffer_size);
+ size_t sz = fread((void *)data.ptrw(), 1, data.size(), stdin);
+ if (sz > 0) {
+ data.resize(sz);
+ return data;
+ }
+ return PackedByteArray();
+}
+
+OS_Unix::StdHandleType OS_Unix::get_stdin_type() const {
+ int h = fileno(stdin);
+ if (h == -1) {
+ return STD_HANDLE_INVALID;
+ }
+
+ if (isatty(h)) {
+ return STD_HANDLE_CONSOLE;
+ }
+ struct stat statbuf;
+ if (fstat(h, &statbuf) < 0) {
+ return STD_HANDLE_UNKNOWN;
+ }
+ if (S_ISFIFO(statbuf.st_mode)) {
+ return STD_HANDLE_PIPE;
+ } else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) {
+ return STD_HANDLE_FILE;
+ }
+ return STD_HANDLE_UNKNOWN;
+}
+
+OS_Unix::StdHandleType OS_Unix::get_stdout_type() const {
+ int h = fileno(stdout);
+ if (h == -1) {
+ return STD_HANDLE_INVALID;
+ }
+
+ if (isatty(h)) {
+ return STD_HANDLE_CONSOLE;
+ }
+ struct stat statbuf;
+ if (fstat(h, &statbuf) < 0) {
+ return STD_HANDLE_UNKNOWN;
+ }
+ if (S_ISFIFO(statbuf.st_mode)) {
+ return STD_HANDLE_PIPE;
+ } else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) {
+ return STD_HANDLE_FILE;
+ }
+ return STD_HANDLE_UNKNOWN;
+}
+
+OS_Unix::StdHandleType OS_Unix::get_stderr_type() const {
+ int h = fileno(stderr);
+ if (h == -1) {
+ return STD_HANDLE_INVALID;
+ }
+
+ if (isatty(h)) {
+ return STD_HANDLE_CONSOLE;
+ }
+ struct stat statbuf;
+ if (fstat(h, &statbuf) < 0) {
+ return STD_HANDLE_UNKNOWN;
+ }
+ if (S_ISFIFO(statbuf.st_mode)) {
+ return STD_HANDLE_PIPE;
+ } else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) {
+ return STD_HANDLE_FILE;
+ }
+ return STD_HANDLE_UNKNOWN;
}
Error OS_Unix::get_entropy(uint8_t *r_buffer, int p_bytes) {
@@ -777,7 +860,7 @@ String OS_Unix::get_locale() const {
}
String locale = get_environment("LANG");
- int tp = locale.find(".");
+ int tp = locale.find_char('.');
if (tp != -1) {
locale = locale.substr(0, tp);
}
diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h
index 3add5df055..2c7920c142 100644
--- a/drivers/unix/os_unix.h
+++ b/drivers/unix/os_unix.h
@@ -58,7 +58,11 @@ public:
virtual Vector<String> get_video_adapter_driver_info() const override;
- virtual String get_stdin_string() override;
+ virtual String get_stdin_string(int64_t p_buffer_size = 1024) override;
+ virtual PackedByteArray get_stdin_buffer(int64_t p_buffer_size = 1024) override;
+ virtual StdHandleType get_stdin_type() const override;
+ virtual StdHandleType get_stdout_type() const override;
+ virtual StdHandleType get_stderr_type() const override;
virtual Error get_entropy(uint8_t *r_buffer, int p_bytes) override;
diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp
index 6eecd850f5..b6e5ed0287 100644
--- a/drivers/vulkan/rendering_device_driver_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp
@@ -2392,7 +2392,9 @@ RDD::CommandQueueFamilyID RenderingDeviceDriverVulkan::command_queue_family_get(
}
}
- ERR_FAIL_COND_V_MSG(picked_family_index >= queue_family_properties.size(), CommandQueueFamilyID(), "A queue family with the requested bits could not be found.");
+ if (picked_family_index >= queue_family_properties.size()) {
+ return CommandQueueFamilyID();
+ }
// Since 0 is a valid index and we use 0 as the error case, we make the index start from 1 instead.
return CommandQueueFamilyID(picked_family_index + 1);
@@ -3032,13 +3034,10 @@ Error RenderingDeviceDriverVulkan::swap_chain_resize(CommandQueueID p_cmd_queue,
#if defined(SWAPPY_FRAME_PACING_ENABLED)
if (swappy_frame_pacer_enable) {
- const double max_fps = Engine::get_singleton()->get_max_fps();
- const uint64_t max_time = max_fps > 0 ? uint64_t((1000.0 * 1000.0 * 1000.0) / max_fps) : 0;
-
SwappyVk_initAndGetRefreshCycleDuration(get_jni_env(), static_cast<OS_Android *>(OS::get_singleton())->get_godot_java()->get_activity(), physical_device,
vk_device, swap_chain->vk_swapchain, &swap_chain->refresh_duration);
SwappyVk_setWindow(vk_device, swap_chain->vk_swapchain, static_cast<OS_Android *>(OS::get_singleton())->get_native_window());
- SwappyVk_setSwapIntervalNS(vk_device, swap_chain->vk_swapchain, MAX(swap_chain->refresh_duration, max_time));
+ SwappyVk_setSwapIntervalNS(vk_device, swap_chain->vk_swapchain, swap_chain->refresh_duration);
enum SwappyModes {
PIPELINE_FORCED_ON,
diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp
index 24a26b56ef..3ddbde72c4 100644
--- a/drivers/windows/dir_access_windows.cpp
+++ b/drivers/windows/dir_access_windows.cpp
@@ -230,7 +230,7 @@ String DirAccessWindows::get_current_dir(bool p_include_drive) const {
return cdir;
} else {
if (_get_root_string().is_empty()) {
- int pos = cdir.find(":");
+ int pos = cdir.find_char(':');
if (pos != -1) {
return cdir.substr(pos + 1);
}
@@ -344,7 +344,7 @@ String DirAccessWindows::get_filesystem_type() const {
return "Network Share";
}
- int unit_end = path.find(":");
+ int unit_end = path.find_char(':');
ERR_FAIL_COND_V(unit_end == -1, String());
String unit = path.substr(0, unit_end + 1) + "\\";
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index 7d2247d41a..4a0e5e5f49 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -64,7 +64,7 @@ bool FileAccessWindows::is_path_invalid(const String &p_path) {
// Check for invalid operating system file.
String fname = p_path.get_file().to_lower();
- int dot = fname.find(".");
+ int dot = fname.find_char('.');
if (dot != -1) {
fname = fname.substr(0, dot);
}
diff --git a/drivers/windows/ip_windows.cpp b/drivers/windows/ip_windows.cpp
new file mode 100644
index 0000000000..4ff368d3f4
--- /dev/null
+++ b/drivers/windows/ip_windows.cpp
@@ -0,0 +1,164 @@
+/**************************************************************************/
+/* ip_windows.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#if defined(WINDOWS_ENABLED)
+
+#include "ip_windows.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#include <iphlpapi.h>
+
+#include <stdio.h>
+
+#include <string.h>
+
+static IPAddress _sockaddr2ip(struct sockaddr *p_addr) {
+ IPAddress ip;
+
+ if (p_addr->sa_family == AF_INET) {
+ struct sockaddr_in *addr = (struct sockaddr_in *)p_addr;
+ ip.set_ipv4((uint8_t *)&(addr->sin_addr));
+ } else if (p_addr->sa_family == AF_INET6) {
+ struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr;
+ ip.set_ipv6(addr6->sin6_addr.s6_addr);
+ }
+
+ return ip;
+}
+
+void IPWindows::_resolve_hostname(List<IPAddress> &r_addresses, const String &p_hostname, Type p_type) const {
+ struct addrinfo hints;
+ struct addrinfo *result = nullptr;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ if (p_type == TYPE_IPV4) {
+ hints.ai_family = AF_INET;
+ } else if (p_type == TYPE_IPV6) {
+ hints.ai_family = AF_INET6;
+ hints.ai_flags = 0;
+ } else {
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_flags = AI_ADDRCONFIG;
+ }
+ hints.ai_flags &= ~AI_NUMERICHOST;
+
+ int s = getaddrinfo(p_hostname.utf8().get_data(), nullptr, &hints, &result);
+ if (s != 0) {
+ print_verbose("getaddrinfo failed! Cannot resolve hostname.");
+ return;
+ }
+
+ if (result == nullptr || result->ai_addr == nullptr) {
+ print_verbose("Invalid response from getaddrinfo.");
+ if (result) {
+ freeaddrinfo(result);
+ }
+ return;
+ }
+
+ struct addrinfo *next = result;
+
+ do {
+ if (next->ai_addr == nullptr) {
+ next = next->ai_next;
+ continue;
+ }
+ IPAddress ip = _sockaddr2ip(next->ai_addr);
+ if (ip.is_valid() && !r_addresses.find(ip)) {
+ r_addresses.push_back(ip);
+ }
+ next = next->ai_next;
+ } while (next);
+
+ freeaddrinfo(result);
+}
+
+void IPWindows::get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const {
+ ULONG buf_size = 1024;
+ IP_ADAPTER_ADDRESSES *addrs;
+
+ while (true) {
+ addrs = (IP_ADAPTER_ADDRESSES *)memalloc(buf_size);
+ int err = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME,
+ nullptr, addrs, &buf_size);
+ if (err == NO_ERROR) {
+ break;
+ }
+ memfree(addrs);
+ if (err == ERROR_BUFFER_OVERFLOW) {
+ continue; // Will go back and alloc the right size.
+ }
+
+ ERR_FAIL_MSG("Call to GetAdaptersAddresses failed with error " + itos(err) + ".");
+ }
+
+ IP_ADAPTER_ADDRESSES *adapter = addrs;
+
+ while (adapter != nullptr) {
+ Interface_Info info;
+ info.name = adapter->AdapterName;
+ info.name_friendly = adapter->FriendlyName;
+ info.index = String::num_uint64(adapter->IfIndex);
+
+ IP_ADAPTER_UNICAST_ADDRESS *address = adapter->FirstUnicastAddress;
+ while (address != nullptr) {
+ int family = address->Address.lpSockaddr->sa_family;
+ if (family != AF_INET && family != AF_INET6) {
+ continue;
+ }
+ info.ip_addresses.push_front(_sockaddr2ip(address->Address.lpSockaddr));
+ address = address->Next;
+ }
+ adapter = adapter->Next;
+ // Only add interface if it has at least one IP.
+ if (info.ip_addresses.size() > 0) {
+ r_interfaces->insert(info.name, info);
+ }
+ }
+
+ memfree(addrs);
+}
+
+void IPWindows::make_default() {
+ _create = _create_unix;
+}
+
+IP *IPWindows::_create_unix() {
+ return memnew(IPWindows);
+}
+
+IPWindows::IPWindows() {
+}
+
+#endif // WINDOWS_ENABLED
diff --git a/modules/text_server_fb/thorvg_bounds_iterator.h b/drivers/windows/ip_windows.h
index afa2c13764..5788d33ee2 100644
--- a/modules/text_server_fb/thorvg_bounds_iterator.h
+++ b/drivers/windows/ip_windows.h
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* thorvg_bounds_iterator.h */
+/* ip_windows.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,31 +28,27 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifndef THORVG_BOUNDS_ITERATOR_H
-#define THORVG_BOUNDS_ITERATOR_H
+#ifndef IP_WINDOWS_H
+#define IP_WINDOWS_H
-#ifdef GDEXTENSION
-// Headers for building as GDExtension plug-in.
+#if defined(WINDOWS_ENABLED)
-#include <godot_cpp/core/mutex_lock.hpp>
-#include <godot_cpp/godot.hpp>
+#include "core/io/ip.h"
-using namespace godot;
+class IPWindows : public IP {
+ GDCLASS(IPWindows, IP);
-#elif defined(GODOT_MODULE)
-// Headers for building as built-in module.
+ virtual void _resolve_hostname(List<IPAddress> &r_addresses, const String &p_hostname, Type p_type = TYPE_ANY) const override;
-#include "core/typedefs.h"
+ static IP *_create_unix();
-#include "modules/modules_enabled.gen.h" // For svg.
-#endif
+public:
+ virtual void get_local_interfaces(HashMap<String, Interface_Info> *r_interfaces) const override;
-#ifdef MODULE_SVG_ENABLED
+ static void make_default();
+ IPWindows();
+};
-#include <thorvg.h>
+#endif // WINDOWS_ENABLED
-void tvg_get_bounds(tvg::Picture *p_picture, float &r_min_x, float &r_min_y, float &r_max_x, float &r_max_y);
-
-#endif // MODULE_SVG_ENABLED
-
-#endif // THORVG_BOUNDS_ITERATOR_H
+#endif // IP_WINDOWS_H
diff --git a/drivers/windows/net_socket_winsock.cpp b/drivers/windows/net_socket_winsock.cpp
new file mode 100644
index 0000000000..3fe7fc619e
--- /dev/null
+++ b/drivers/windows/net_socket_winsock.cpp
@@ -0,0 +1,613 @@
+/**************************************************************************/
+/* net_socket_winsock.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifdef WINDOWS_ENABLED
+
+#include "net_socket_winsock.h"
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#include <mswsock.h>
+// Workaround missing flag in MinGW
+#if defined(__MINGW32__) && !defined(SIO_UDP_NETRESET)
+#define SIO_UDP_NETRESET _WSAIOW(IOC_VENDOR, 15)
+#endif
+
+size_t NetSocketWinSock::_set_addr_storage(struct sockaddr_storage *p_addr, const IPAddress &p_ip, uint16_t p_port, IP::Type p_ip_type) {
+ memset(p_addr, 0, sizeof(struct sockaddr_storage));
+ if (p_ip_type == IP::TYPE_IPV6 || p_ip_type == IP::TYPE_ANY) { // IPv6 socket.
+
+ // IPv6 only socket with IPv4 address.
+ ERR_FAIL_COND_V(!p_ip.is_wildcard() && p_ip_type == IP::TYPE_IPV6 && p_ip.is_ipv4(), 0);
+
+ struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr;
+ addr6->sin6_family = AF_INET6;
+ addr6->sin6_port = htons(p_port);
+ if (p_ip.is_valid()) {
+ memcpy(&addr6->sin6_addr.s6_addr, p_ip.get_ipv6(), 16);
+ } else {
+ addr6->sin6_addr = in6addr_any;
+ }
+ return sizeof(sockaddr_in6);
+ } else { // IPv4 socket.
+
+ // IPv4 socket with IPv6 address.
+ ERR_FAIL_COND_V(!p_ip.is_wildcard() && !p_ip.is_ipv4(), 0);
+
+ struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr;
+ addr4->sin_family = AF_INET;
+ addr4->sin_port = htons(p_port); // Short, network byte order.
+
+ if (p_ip.is_valid()) {
+ memcpy(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 4);
+ } else {
+ addr4->sin_addr.s_addr = INADDR_ANY;
+ }
+
+ return sizeof(sockaddr_in);
+ }
+}
+
+void NetSocketWinSock::_set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_ip, uint16_t *r_port) {
+ if (p_addr->ss_family == AF_INET) {
+ struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr;
+ if (r_ip) {
+ r_ip->set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr));
+ }
+ if (r_port) {
+ *r_port = ntohs(addr4->sin_port);
+ }
+ } else if (p_addr->ss_family == AF_INET6) {
+ struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr;
+ if (r_ip) {
+ r_ip->set_ipv6(addr6->sin6_addr.s6_addr);
+ }
+ if (r_port) {
+ *r_port = ntohs(addr6->sin6_port);
+ }
+ }
+}
+
+NetSocket *NetSocketWinSock::_create_func() {
+ return memnew(NetSocketWinSock);
+}
+
+void NetSocketWinSock::make_default() {
+ ERR_FAIL_COND(_create != nullptr);
+
+ WSADATA data;
+ WSAStartup(MAKEWORD(2, 2), &data);
+ _create = _create_func;
+}
+
+void NetSocketWinSock::cleanup() {
+ ERR_FAIL_COND(_create == nullptr);
+
+ WSACleanup();
+ _create = nullptr;
+}
+
+NetSocketWinSock::NetSocketWinSock() {
+}
+
+NetSocketWinSock::~NetSocketWinSock() {
+ close();
+}
+
+NetSocketWinSock::NetError NetSocketWinSock::_get_socket_error() const {
+ int err = WSAGetLastError();
+ if (err == WSAEISCONN) {
+ return ERR_NET_IS_CONNECTED;
+ }
+ if (err == WSAEINPROGRESS || err == WSAEALREADY) {
+ return ERR_NET_IN_PROGRESS;
+ }
+ if (err == WSAEWOULDBLOCK) {
+ return ERR_NET_WOULD_BLOCK;
+ }
+ if (err == WSAEADDRINUSE || err == WSAEADDRNOTAVAIL) {
+ return ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE;
+ }
+ if (err == WSAEACCES) {
+ return ERR_NET_UNAUTHORIZED;
+ }
+ if (err == WSAEMSGSIZE || err == WSAENOBUFS) {
+ return ERR_NET_BUFFER_TOO_SMALL;
+ }
+ print_verbose("Socket error: " + itos(err) + ".");
+ return ERR_NET_OTHER;
+}
+
+bool NetSocketWinSock::_can_use_ip(const IPAddress &p_ip, const bool p_for_bind) const {
+ if (p_for_bind && !(p_ip.is_valid() || p_ip.is_wildcard())) {
+ return false;
+ } else if (!p_for_bind && !p_ip.is_valid()) {
+ return false;
+ }
+ // Check if socket support this IP type.
+ IP::Type type = p_ip.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6;
+ return !(_ip_type != IP::TYPE_ANY && !p_ip.is_wildcard() && _ip_type != type);
+}
+
+_FORCE_INLINE_ Error NetSocketWinSock::_change_multicast_group(IPAddress p_ip, String p_if_name, bool p_add) {
+ ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(!_can_use_ip(p_ip, false), ERR_INVALID_PARAMETER);
+
+ // Need to force level and af_family to IP(v4) when using dual stacking and provided multicast group is IPv4.
+ IP::Type type = _ip_type == IP::TYPE_ANY && p_ip.is_ipv4() ? IP::TYPE_IPV4 : _ip_type;
+ // This needs to be the proper level for the multicast group, no matter if the socket is dual stacking.
+ int level = type == IP::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
+ int ret = -1;
+
+ IPAddress if_ip;
+ uint32_t if_v6id = 0;
+ HashMap<String, IP::Interface_Info> if_info;
+ IP::get_singleton()->get_local_interfaces(&if_info);
+ for (KeyValue<String, IP::Interface_Info> &E : if_info) {
+ IP::Interface_Info &c = E.value;
+ if (c.name != p_if_name) {
+ continue;
+ }
+
+ if_v6id = (uint32_t)c.index.to_int();
+ if (type == IP::TYPE_IPV6) {
+ break; // IPv6 uses index.
+ }
+
+ for (const IPAddress &F : c.ip_addresses) {
+ if (!F.is_ipv4()) {
+ continue; // Wrong IP type.
+ }
+ if_ip = F;
+ break;
+ }
+ break;
+ }
+
+ if (level == IPPROTO_IP) {
+ ERR_FAIL_COND_V(!if_ip.is_valid(), ERR_INVALID_PARAMETER);
+ struct ip_mreq greq;
+ int sock_opt = p_add ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
+ memcpy(&greq.imr_multiaddr, p_ip.get_ipv4(), 4);
+ memcpy(&greq.imr_interface, if_ip.get_ipv4(), 4);
+ ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq));
+ } else {
+ struct ipv6_mreq greq;
+ int sock_opt = p_add ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP;
+ memcpy(&greq.ipv6mr_multiaddr, p_ip.get_ipv6(), 16);
+ greq.ipv6mr_interface = if_v6id;
+ ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq));
+ }
+ ERR_FAIL_COND_V(ret != 0, FAILED);
+
+ return OK;
+}
+
+void NetSocketWinSock::_set_socket(SOCKET p_sock, IP::Type p_ip_type, bool p_is_stream) {
+ _sock = p_sock;
+ _ip_type = p_ip_type;
+ _is_stream = p_is_stream;
+}
+
+Error NetSocketWinSock::open(Type p_sock_type, IP::Type &ip_type) {
+ ERR_FAIL_COND_V(is_open(), ERR_ALREADY_IN_USE);
+ ERR_FAIL_COND_V(ip_type > IP::TYPE_ANY || ip_type < IP::TYPE_NONE, ERR_INVALID_PARAMETER);
+
+ int family = ip_type == IP::TYPE_IPV4 ? AF_INET : AF_INET6;
+ int protocol = p_sock_type == TYPE_TCP ? IPPROTO_TCP : IPPROTO_UDP;
+ int type = p_sock_type == TYPE_TCP ? SOCK_STREAM : SOCK_DGRAM;
+ _sock = socket(family, type, protocol);
+
+ if (_sock == INVALID_SOCKET && ip_type == IP::TYPE_ANY) {
+ // Careful here, changing the referenced parameter so the caller knows that we are using an IPv4 socket
+ // in place of a dual stack one, and further calls to _set_sock_addr will work as expected.
+ ip_type = IP::TYPE_IPV4;
+ family = AF_INET;
+ _sock = socket(family, type, protocol);
+ }
+
+ ERR_FAIL_COND_V(_sock == INVALID_SOCKET, FAILED);
+ _ip_type = ip_type;
+
+ if (family == AF_INET6) {
+ // Select IPv4 over IPv6 mapping.
+ set_ipv6_only_enabled(ip_type != IP::TYPE_ANY);
+ }
+
+ if (protocol == IPPROTO_UDP) {
+ // Make sure to disable broadcasting for UDP sockets.
+ // Depending on the OS, this option might or might not be enabled by default. Let's normalize it.
+ set_broadcasting_enabled(false);
+ }
+
+ _is_stream = p_sock_type == TYPE_TCP;
+
+ if (!_is_stream) {
+ // Disable windows feature/bug reporting WSAECONNRESET/WSAENETRESET when
+ // recv/recvfrom and an ICMP reply was received from a previous send/sendto.
+ unsigned long disable = 0;
+ if (ioctlsocket(_sock, SIO_UDP_CONNRESET, &disable) == SOCKET_ERROR) {
+ print_verbose("Unable to turn off UDP WSAECONNRESET behavior on Windows.");
+ }
+ if (ioctlsocket(_sock, SIO_UDP_NETRESET, &disable) == SOCKET_ERROR) {
+ // This feature seems not to be supported on wine.
+ print_verbose("Unable to turn off UDP WSAENETRESET behavior on Windows.");
+ }
+ }
+ return OK;
+}
+
+void NetSocketWinSock::close() {
+ if (_sock != INVALID_SOCKET) {
+ closesocket(_sock);
+ }
+
+ _sock = INVALID_SOCKET;
+ _ip_type = IP::TYPE_NONE;
+ _is_stream = false;
+}
+
+Error NetSocketWinSock::bind(IPAddress p_addr, uint16_t p_port) {
+ ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(!_can_use_ip(p_addr, true), ERR_INVALID_PARAMETER);
+
+ sockaddr_storage addr;
+ size_t addr_size = _set_addr_storage(&addr, p_addr, p_port, _ip_type);
+
+ if (::bind(_sock, (struct sockaddr *)&addr, addr_size) != 0) {
+ NetError err = _get_socket_error();
+ print_verbose("Failed to bind socket. Error: " + itos(err) + ".");
+ close();
+ return ERR_UNAVAILABLE;
+ }
+
+ return OK;
+}
+
+Error NetSocketWinSock::listen(int p_max_pending) {
+ ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
+
+ if (::listen(_sock, p_max_pending) != 0) {
+ _get_socket_error();
+ print_verbose("Failed to listen from socket.");
+ close();
+ return FAILED;
+ }
+
+ return OK;
+}
+
+Error NetSocketWinSock::connect_to_host(IPAddress p_host, uint16_t p_port) {
+ ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(!_can_use_ip(p_host, false), ERR_INVALID_PARAMETER);
+
+ struct sockaddr_storage addr;
+ size_t addr_size = _set_addr_storage(&addr, p_host, p_port, _ip_type);
+
+ if (::WSAConnect(_sock, (struct sockaddr *)&addr, addr_size, nullptr, nullptr, nullptr, nullptr) != 0) {
+ NetError err = _get_socket_error();
+
+ switch (err) {
+ // We are already connected.
+ case ERR_NET_IS_CONNECTED:
+ return OK;
+ // Still waiting to connect, try again in a while.
+ case ERR_NET_WOULD_BLOCK:
+ case ERR_NET_IN_PROGRESS:
+ return ERR_BUSY;
+ default:
+ print_verbose("Connection to remote host failed.");
+ close();
+ return FAILED;
+ }
+ }
+
+ return OK;
+}
+
+Error NetSocketWinSock::poll(PollType p_type, int p_timeout) const {
+ ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
+
+ bool ready = false;
+ fd_set rd, wr, ex;
+ fd_set *rdp = nullptr;
+ fd_set *wrp = nullptr;
+ FD_ZERO(&rd);
+ FD_ZERO(&wr);
+ FD_ZERO(&ex);
+ FD_SET(_sock, &ex);
+ struct timeval timeout = { p_timeout / 1000, (p_timeout % 1000) * 1000 };
+ // For blocking operation, pass nullptr timeout pointer to select.
+ struct timeval *tp = nullptr;
+ if (p_timeout >= 0) {
+ // If timeout is non-negative, we want to specify the timeout instead.
+ tp = &timeout;
+ }
+
+ switch (p_type) {
+ case POLL_TYPE_IN:
+ FD_SET(_sock, &rd);
+ rdp = &rd;
+ break;
+ case POLL_TYPE_OUT:
+ FD_SET(_sock, &wr);
+ wrp = &wr;
+ break;
+ case POLL_TYPE_IN_OUT:
+ FD_SET(_sock, &rd);
+ FD_SET(_sock, &wr);
+ rdp = &rd;
+ wrp = &wr;
+ }
+ // WSAPoll is broken: https://daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken/.
+ int ret = select(1, rdp, wrp, &ex, tp);
+
+ if (ret == SOCKET_ERROR) {
+ return FAILED;
+ }
+
+ if (ret == 0) {
+ return ERR_BUSY;
+ }
+
+ if (FD_ISSET(_sock, &ex)) {
+ _get_socket_error();
+ print_verbose("Exception when polling socket.");
+ return FAILED;
+ }
+
+ if (rdp && FD_ISSET(_sock, rdp)) {
+ ready = true;
+ }
+ if (wrp && FD_ISSET(_sock, wrp)) {
+ ready = true;
+ }
+
+ return ready ? OK : ERR_BUSY;
+}
+
+Error NetSocketWinSock::recv(uint8_t *p_buffer, int p_len, int &r_read) {
+ ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
+
+ r_read = ::recv(_sock, (char *)p_buffer, p_len, 0);
+
+ if (r_read < 0) {
+ NetError err = _get_socket_error();
+ if (err == ERR_NET_WOULD_BLOCK) {
+ return ERR_BUSY;
+ }
+
+ if (err == ERR_NET_BUFFER_TOO_SMALL) {
+ return ERR_OUT_OF_MEMORY;
+ }
+
+ return FAILED;
+ }
+
+ return OK;
+}
+
+Error NetSocketWinSock::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek) {
+ ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
+
+ struct sockaddr_storage from;
+ socklen_t len = sizeof(struct sockaddr_storage);
+ memset(&from, 0, len);
+
+ r_read = ::recvfrom(_sock, (char *)p_buffer, p_len, p_peek ? MSG_PEEK : 0, (struct sockaddr *)&from, &len);
+
+ if (r_read < 0) {
+ NetError err = _get_socket_error();
+ if (err == ERR_NET_WOULD_BLOCK) {
+ return ERR_BUSY;
+ }
+
+ if (err == ERR_NET_BUFFER_TOO_SMALL) {
+ return ERR_OUT_OF_MEMORY;
+ }
+
+ return FAILED;
+ }
+
+ if (from.ss_family == AF_INET) {
+ struct sockaddr_in *sin_from = (struct sockaddr_in *)&from;
+ r_ip.set_ipv4((uint8_t *)&sin_from->sin_addr);
+ r_port = ntohs(sin_from->sin_port);
+ } else if (from.ss_family == AF_INET6) {
+ struct sockaddr_in6 *s6_from = (struct sockaddr_in6 *)&from;
+ r_ip.set_ipv6((uint8_t *)&s6_from->sin6_addr);
+ r_port = ntohs(s6_from->sin6_port);
+ } else {
+ // Unsupported socket family, should never happen.
+ ERR_FAIL_V(FAILED);
+ }
+
+ return OK;
+}
+
+Error NetSocketWinSock::send(const uint8_t *p_buffer, int p_len, int &r_sent) {
+ ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
+
+ int flags = 0;
+ r_sent = ::send(_sock, (const char *)p_buffer, p_len, flags);
+
+ if (r_sent < 0) {
+ NetError err = _get_socket_error();
+ if (err == ERR_NET_WOULD_BLOCK) {
+ return ERR_BUSY;
+ }
+ if (err == ERR_NET_BUFFER_TOO_SMALL) {
+ return ERR_OUT_OF_MEMORY;
+ }
+
+ return FAILED;
+ }
+
+ return OK;
+}
+
+Error NetSocketWinSock::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) {
+ ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
+
+ struct sockaddr_storage addr;
+ size_t addr_size = _set_addr_storage(&addr, p_ip, p_port, _ip_type);
+ r_sent = ::sendto(_sock, (const char *)p_buffer, p_len, 0, (struct sockaddr *)&addr, addr_size);
+
+ if (r_sent < 0) {
+ NetError err = _get_socket_error();
+ if (err == ERR_NET_WOULD_BLOCK) {
+ return ERR_BUSY;
+ }
+ if (err == ERR_NET_BUFFER_TOO_SMALL) {
+ return ERR_OUT_OF_MEMORY;
+ }
+
+ return FAILED;
+ }
+
+ return OK;
+}
+
+Error NetSocketWinSock::set_broadcasting_enabled(bool p_enabled) {
+ ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
+ // IPv6 has no broadcast support.
+ if (_ip_type == IP::TYPE_IPV6) {
+ return ERR_UNAVAILABLE;
+ }
+
+ int par = p_enabled ? 1 : 0;
+ if (setsockopt(_sock, SOL_SOCKET, SO_BROADCAST, (const char *)&par, sizeof(int)) != 0) {
+ WARN_PRINT("Unable to change broadcast setting.");
+ return FAILED;
+ }
+ return OK;
+}
+
+void NetSocketWinSock::set_blocking_enabled(bool p_enabled) {
+ ERR_FAIL_COND(!is_open());
+
+ int ret = 0;
+ unsigned long par = p_enabled ? 0 : 1;
+ ret = ioctlsocket(_sock, FIONBIO, &par);
+ if (ret != 0) {
+ WARN_PRINT("Unable to change non-block mode.");
+ }
+}
+
+void NetSocketWinSock::set_ipv6_only_enabled(bool p_enabled) {
+ ERR_FAIL_COND(!is_open());
+ // This option is only available in IPv6 sockets.
+ ERR_FAIL_COND(_ip_type == IP::TYPE_IPV4);
+
+ int par = p_enabled ? 1 : 0;
+ if (setsockopt(_sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&par, sizeof(int)) != 0) {
+ WARN_PRINT("Unable to change IPv4 address mapping over IPv6 option.");
+ }
+}
+
+void NetSocketWinSock::set_tcp_no_delay_enabled(bool p_enabled) {
+ ERR_FAIL_COND(!is_open());
+ ERR_FAIL_COND(!_is_stream); // Not TCP.
+
+ int par = p_enabled ? 1 : 0;
+ if (setsockopt(_sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&par, sizeof(int)) < 0) {
+ WARN_PRINT("Unable to set TCP no delay option.");
+ }
+}
+
+void NetSocketWinSock::set_reuse_address_enabled(bool p_enabled) {
+ ERR_FAIL_COND(!is_open());
+
+ // On Windows, enabling SO_REUSEADDR actually would also enable reuse port, very bad on TCP. Denying...
+ // Windows does not have this option, SO_REUSEADDR in this magical world means SO_REUSEPORT
+}
+
+bool NetSocketWinSock::is_open() const {
+ return _sock != INVALID_SOCKET;
+}
+
+int NetSocketWinSock::get_available_bytes() const {
+ ERR_FAIL_COND_V(!is_open(), -1);
+
+ unsigned long len;
+ int ret = ioctlsocket(_sock, FIONREAD, &len);
+ if (ret == -1) {
+ _get_socket_error();
+ print_verbose("Error when checking available bytes on socket.");
+ return -1;
+ }
+ return len;
+}
+
+Error NetSocketWinSock::get_socket_address(IPAddress *r_ip, uint16_t *r_port) const {
+ ERR_FAIL_COND_V(!is_open(), FAILED);
+
+ struct sockaddr_storage saddr;
+ socklen_t len = sizeof(saddr);
+ if (getsockname(_sock, (struct sockaddr *)&saddr, &len) != 0) {
+ _get_socket_error();
+ print_verbose("Error when reading local socket address.");
+ return FAILED;
+ }
+ _set_ip_port(&saddr, r_ip, r_port);
+ return OK;
+}
+
+Ref<NetSocket> NetSocketWinSock::accept(IPAddress &r_ip, uint16_t &r_port) {
+ Ref<NetSocket> out;
+ ERR_FAIL_COND_V(!is_open(), out);
+
+ struct sockaddr_storage their_addr;
+ socklen_t size = sizeof(their_addr);
+ SOCKET fd = ::accept(_sock, (struct sockaddr *)&their_addr, &size);
+ if (fd == INVALID_SOCKET) {
+ _get_socket_error();
+ print_verbose("Error when accepting socket connection.");
+ return out;
+ }
+
+ _set_ip_port(&their_addr, &r_ip, &r_port);
+
+ NetSocketWinSock *ns = memnew(NetSocketWinSock);
+ ns->_set_socket(fd, _ip_type, _is_stream);
+ ns->set_blocking_enabled(false);
+ return Ref<NetSocket>(ns);
+}
+
+Error NetSocketWinSock::join_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
+ return _change_multicast_group(p_multi_address, p_if_name, true);
+}
+
+Error NetSocketWinSock::leave_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
+ return _change_multicast_group(p_multi_address, p_if_name, false);
+}
+
+#endif // WINDOWS_ENABLED
diff --git a/drivers/windows/net_socket_winsock.h b/drivers/windows/net_socket_winsock.h
new file mode 100644
index 0000000000..5c3445b8cb
--- /dev/null
+++ b/drivers/windows/net_socket_winsock.h
@@ -0,0 +1,102 @@
+/**************************************************************************/
+/* net_socket_winsock.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef NET_SOCKET_WINSOCK_H
+#define NET_SOCKET_WINSOCK_H
+
+#ifdef WINDOWS_ENABLED
+
+#include "core/io/net_socket.h"
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+class NetSocketWinSock : public NetSocket {
+private:
+ SOCKET _sock = INVALID_SOCKET;
+ IP::Type _ip_type = IP::TYPE_NONE;
+ bool _is_stream = false;
+
+ enum NetError {
+ ERR_NET_WOULD_BLOCK,
+ ERR_NET_IS_CONNECTED,
+ ERR_NET_IN_PROGRESS,
+ ERR_NET_ADDRESS_INVALID_OR_UNAVAILABLE,
+ ERR_NET_UNAUTHORIZED,
+ ERR_NET_BUFFER_TOO_SMALL,
+ ERR_NET_OTHER,
+ };
+
+ NetError _get_socket_error() const;
+ void _set_socket(SOCKET p_sock, IP::Type p_ip_type, bool p_is_stream);
+ _FORCE_INLINE_ Error _change_multicast_group(IPAddress p_ip, String p_if_name, bool p_add);
+
+protected:
+ static NetSocket *_create_func();
+
+ bool _can_use_ip(const IPAddress &p_ip, const bool p_for_bind) const;
+
+public:
+ static void make_default();
+ static void cleanup();
+ static void _set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_ip, uint16_t *r_port);
+ static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IPAddress &p_ip, uint16_t p_port, IP::Type p_ip_type);
+
+ virtual Error open(Type p_sock_type, IP::Type &ip_type) override;
+ virtual void close() override;
+ virtual Error bind(IPAddress p_addr, uint16_t p_port) override;
+ virtual Error listen(int p_max_pending) override;
+ virtual Error connect_to_host(IPAddress p_host, uint16_t p_port) override;
+ virtual Error poll(PollType p_type, int timeout) const override;
+ virtual Error recv(uint8_t *p_buffer, int p_len, int &r_read) override;
+ virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek = false) override;
+ virtual Error send(const uint8_t *p_buffer, int p_len, int &r_sent) override;
+ virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) override;
+ virtual Ref<NetSocket> accept(IPAddress &r_ip, uint16_t &r_port) override;
+
+ virtual bool is_open() const override;
+ virtual int get_available_bytes() const override;
+ virtual Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) const override;
+
+ virtual Error set_broadcasting_enabled(bool p_enabled) override;
+ virtual void set_blocking_enabled(bool p_enabled) override;
+ virtual void set_ipv6_only_enabled(bool p_enabled) override;
+ virtual void set_tcp_no_delay_enabled(bool p_enabled) override;
+ virtual void set_reuse_address_enabled(bool p_enabled) override;
+ virtual Error join_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) override;
+ virtual Error leave_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) override;
+
+ NetSocketWinSock();
+ ~NetSocketWinSock() override;
+};
+
+#endif // WINDOWS_ENABLED
+
+#endif // NET_SOCKET_WINSOCK_H
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index 8d7c6a1f16..36ca417638 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -275,7 +275,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
}
String base_path = animation->track_get_path(i);
- int end = base_path.find(":");
+ int end = base_path.find_char(':');
if (end != -1) {
base_path = base_path.substr(0, end + 1);
}
@@ -1650,7 +1650,7 @@ void AnimationBezierTrackEdit::_zoom_callback(float p_zoom_factor, Vector2 p_ori
Ref<InputEventWithModifiers> iewm = p_event;
if (iewm.is_valid() && iewm->is_alt_pressed()) {
// Alternate zoom (doesn't affect timeline).
- timeline_v_zoom = CLAMP(timeline_v_zoom * p_zoom_factor, 0.000001, 100000);
+ timeline_v_zoom = CLAMP(timeline_v_zoom / p_zoom_factor, 0.000001, 100000);
} else {
float zoom_factor = p_zoom_factor > 1.0 ? AnimationTimelineEdit::SCROLL_ZOOM_FACTOR_IN : AnimationTimelineEdit::SCROLL_ZOOM_FACTOR_OUT;
timeline->_zoom_callback(zoom_factor, p_origin, p_event);
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 076ba6d905..1a612a3e55 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -1400,12 +1400,26 @@ void AnimationTimelineEdit::_anim_loop_pressed() {
undo_redo->add_undo_method(this, "update_values");
undo_redo->commit_action();
} else {
- String base_path = animation->get_path();
- if (FileAccess::exists(base_path + ".import")) {
- EditorNode::get_singleton()->show_warning(TTR("Can't change loop mode on animation instanced from imported scene."));
+ String base = animation->get_path();
+ int srpos = base.find("::");
+ if (srpos != -1) {
+ base = animation->get_path().substr(0, srpos);
+ }
+
+ if (FileAccess::exists(base + ".import")) {
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ EditorNode::get_singleton()->show_warning(TTR("Can't change loop mode on animation instanced from an imported scene.\n\nTo change this animation's loop mode, navigate to the scene's Advanced Import settings and select the animation.\nYou can then change the loop mode from the inspector menu."));
+ } else {
+ EditorNode::get_singleton()->show_warning(TTR("Can't change loop mode on animation instanced from an imported resource."));
+ }
} else {
- EditorNode::get_singleton()->show_warning(TTR("Can't change loop mode on animation embedded in another scene."));
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ EditorNode::get_singleton()->show_warning(TTR("Can't change loop mode on animation embedded in another scene.\n\nYou must open this scene and change the animation's loop mode from there."));
+ } else {
+ EditorNode::get_singleton()->show_warning(TTR("Can't change loop mode on animation embedded in another resource."));
+ }
}
+
update_values();
}
}
@@ -2191,7 +2205,7 @@ void AnimationTrackEdit::_notification(int p_what) {
offset = offset * scale + limit;
Color marker_color = animation->get_marker_color(marker);
marker_color.a = 0.2;
- draw_line(Point2(offset, 0), Point2(offset, get_size().height), marker_color);
+ draw_line(Point2(offset, 0), Point2(offset, get_size().height), marker_color, Math::round(EDSCALE));
}
}
}
@@ -3647,7 +3661,7 @@ void AnimationTrackEditGroup::_notification(int p_what) {
offset = offset * scale + limit;
Color marker_color = editor->get_current_animation()->get_marker_color(marker);
marker_color.a = 0.2;
- draw_line(Point2(offset, 0), Point2(offset, get_size().height), marker_color);
+ draw_line(Point2(offset, 0), Point2(offset, get_size().height), marker_color, Math::round(EDSCALE));
}
}
}
@@ -4340,7 +4354,7 @@ void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_p
if (track_path == np) {
actual_value = value; // All good.
} else {
- int sep = track_path.rfind(":");
+ int sep = track_path.rfind_char(':');
if (sep != -1) {
String base_path = track_path.substr(0, sep);
if (base_path == np) {
@@ -6495,7 +6509,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
path = NodePath(node->get_path().get_names(), path.get_subnames(), true); // Store full path instead for copying.
} else {
text = path;
- int sep = text.find(":");
+ int sep = text.find_char(':');
if (sep != -1) {
text = text.substr(sep + 1, text.length());
}
@@ -6628,6 +6642,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
case EDIT_SCALE_SELECTION:
case EDIT_SCALE_FROM_CURSOR: {
scale_dialog->popup_centered(Size2(200, 100) * EDSCALE);
+ scale->get_line_edit()->grab_focus();
} break;
case EDIT_SCALE_CONFIRM: {
if (selection.is_empty()) {
@@ -7364,7 +7379,6 @@ void AnimationTrackEditor::_update_snap_unit() {
}
if (timeline->is_using_fps()) {
- _clear_selection(true); // Needs to recreate a spinbox of the KeyEdit.
snap_unit = 1.0 / step->get_value();
} else {
if (fps_compat->is_pressed()) {
@@ -7383,16 +7397,17 @@ void AnimationTrackEditor::_update_snap_unit() {
float AnimationTrackEditor::snap_time(float p_value, bool p_relative) {
if (is_snap_keys_enabled()) {
+ double current_snap = snap_unit;
if (Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
// Use more precise snapping when holding Shift.
- snap_unit *= 0.25;
+ current_snap *= 0.25;
}
if (p_relative) {
- double rel = Math::fmod(timeline->get_value(), snap_unit);
- p_value = Math::snapped(p_value + rel, snap_unit) - rel;
+ double rel = Math::fmod(timeline->get_value(), current_snap);
+ p_value = Math::snapped(p_value + rel, current_snap) - rel;
} else {
- p_value = Math::snapped(p_value, snap_unit);
+ p_value = Math::snapped(p_value, current_snap);
}
}
@@ -7875,10 +7890,13 @@ AnimationTrackEditor::AnimationTrackEditor() {
scale->set_min(-99999);
scale->set_max(99999);
scale->set_step(0.001);
+ scale->set_select_all_on_focus(true);
vbc->add_margin_child(TTR("Scale Ratio:"), scale);
- scale_dialog->connect(SceneStringName(confirmed), callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_SCALE_CONFIRM));
+ scale_dialog->connect(SceneStringName(confirmed), callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_SCALE_CONFIRM), CONNECT_DEFERRED);
add_child(scale_dialog);
+ scale_dialog->register_text_enter(scale->get_line_edit());
+
//
ease_dialog = memnew(ConfirmationDialog);
ease_dialog->set_title(TTR("Select Transition and Easing"));
@@ -7982,6 +8000,11 @@ AnimationTrackEditor::~AnimationTrackEditor() {
// AnimationTrackKeyEditEditorPlugin.
+void AnimationTrackKeyEditEditor::_time_edit_spun() {
+ _time_edit_entered();
+ _time_edit_exited();
+}
+
void AnimationTrackKeyEditEditor::_time_edit_entered() {
int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX);
if (key == -1) {
@@ -8009,7 +8032,7 @@ void AnimationTrackKeyEditEditor::_time_edit_exited() {
int existing = animation->track_find_key(track, new_time, Animation::FIND_MODE_APPROX);
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Animation Change Keyframe Time"), UndoRedo::MERGE_ENDS);
+ undo_redo->create_action(TTR("Animation Change Keyframe Time"));
if (existing != -1) {
undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", track, animation->track_get_key_time(track, existing));
@@ -8056,6 +8079,7 @@ AnimationTrackKeyEditEditor::AnimationTrackKeyEditEditor(Ref<Animation> p_animat
spinner->set_min(0);
spinner->set_allow_greater(true);
spinner->set_allow_lesser(true);
+ add_child(spinner);
if (use_fps) {
spinner->set_step(FPS_DECIMAL);
@@ -8064,14 +8088,13 @@ AnimationTrackKeyEditEditor::AnimationTrackKeyEditEditor(Ref<Animation> p_animat
fps = 1.0 / fps;
}
spinner->set_value(key_ofs * fps);
+ spinner->connect("updown_pressed", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_spun), CONNECT_DEFERRED);
} else {
spinner->set_step(SECOND_DECIMAL);
spinner->set_value(key_ofs);
spinner->set_max(animation->get_length());
}
- add_child(spinner);
-
spinner->connect("grabbed", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_entered), CONNECT_DEFERRED);
spinner->connect("ungrabbed", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_exited), CONNECT_DEFERRED);
spinner->connect("value_focus_entered", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_entered), CONNECT_DEFERRED);
@@ -8306,9 +8329,6 @@ void AnimationMarkerEdit::_notification(int p_what) {
Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));
Color color = get_theme_color(SceneStringName(font_color), SNAME("Label"));
- int hsep = get_theme_constant(SNAME("h_separation"), SNAME("ItemList"));
- Color linecolor = color;
- linecolor.a = 0.2;
// SECTION PREVIEW //
@@ -8367,31 +8387,21 @@ void AnimationMarkerEdit::_notification(int p_what) {
draw_key(name, scale, int(offset), is_selected, limit, limit_end);
- const int font_size = 16;
+ const int font_size = 12 * EDSCALE;
Size2 string_size = font->get_string_size(name, HORIZONTAL_ALIGNMENT_LEFT, -1.0, font_size);
if (int(offset) <= limit_end && int(offset) >= limit && should_show_all_marker_names) {
float bottom = get_size().height + string_size.y - font->get_descent(font_size);
float extrusion = MAX(0, offset + string_size.x - limit_end); // How much the string would extrude outside limit_end if unadjusted.
Color marker_color = animation->get_marker_color(name);
- draw_string(font, Point2(offset - extrusion, bottom), name, HORIZONTAL_ALIGNMENT_LEFT, -1.0, font_size, marker_color);
- draw_string_outline(font, Point2(offset - extrusion, bottom), name, HORIZONTAL_ALIGNMENT_LEFT, -1.0, font_size, 1, color);
+ float margin = 4 * EDSCALE;
+ Point2 pos = Point2(offset - extrusion + margin, bottom + margin);
+ draw_string(font, pos, name, HORIZONTAL_ALIGNMENT_LEFT, -1.0, font_size, marker_color);
+ draw_string_outline(font, pos, name, HORIZONTAL_ALIGNMENT_LEFT, -1.0, font_size, 1, color);
}
}
}
draw_fg(limit, get_size().width - timeline->get_buttons_width());
-
- // BUTTONS //
-
- {
- int ofs = get_size().width - timeline->get_buttons_width();
-
- draw_line(Point2(ofs, 0), Point2(ofs, get_size().height), linecolor, Math::round(EDSCALE));
-
- ofs += hsep;
- }
-
- draw_line(Vector2(0, get_size().height), get_size(), linecolor, Math::round(EDSCALE));
} break;
case NOTIFICATION_MOUSE_ENTER:
@@ -9192,9 +9202,6 @@ void AnimationMultiMarkerKeyEdit::_get_property_list(List<PropertyInfo> *p_list)
// AnimationMarkerKeyEditEditorPlugin
-void AnimationMarkerKeyEditEditor::_time_edit_entered() {
-}
-
void AnimationMarkerKeyEditEditor::_time_edit_exited() {
real_t new_time = spinner->get_value();
@@ -9213,7 +9220,7 @@ void AnimationMarkerKeyEditEditor::_time_edit_exited() {
}
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Animation Change Marker Time"), UndoRedo::MERGE_ENDS);
+ undo_redo->create_action(TTR("Animation Change Marker Time"));
Color color = animation->get_marker_color(marker_name);
undo_redo->add_do_method(animation.ptr(), "add_marker", marker_name, new_time);
@@ -9254,6 +9261,7 @@ AnimationMarkerKeyEditEditor::AnimationMarkerKeyEditEditor(Ref<Animation> p_anim
spinner->set_min(0);
spinner->set_allow_greater(true);
spinner->set_allow_lesser(true);
+ add_child(spinner);
float time = animation->get_marker_time(marker_name);
@@ -9264,17 +9272,14 @@ AnimationMarkerKeyEditEditor::AnimationMarkerKeyEditEditor(Ref<Animation> p_anim
fps = 1.0 / fps;
}
spinner->set_value(time * fps);
+ spinner->connect("updown_pressed", callable_mp(this, &AnimationMarkerKeyEditEditor::_time_edit_exited), CONNECT_DEFERRED);
} else {
spinner->set_step(SECOND_DECIMAL);
spinner->set_value(time);
spinner->set_max(animation->get_length());
}
- add_child(spinner);
-
- spinner->connect("grabbed", callable_mp(this, &AnimationMarkerKeyEditEditor::_time_edit_entered), CONNECT_DEFERRED);
spinner->connect("ungrabbed", callable_mp(this, &AnimationMarkerKeyEditEditor::_time_edit_exited), CONNECT_DEFERRED);
- spinner->connect("value_focus_entered", callable_mp(this, &AnimationMarkerKeyEditEditor::_time_edit_entered), CONNECT_DEFERRED);
spinner->connect("value_focus_exited", callable_mp(this, &AnimationMarkerKeyEditEditor::_time_edit_exited), CONNECT_DEFERRED);
}
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index e7271f1941..f17386b0c9 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -977,6 +977,7 @@ class AnimationTrackKeyEditEditor : public EditorProperty {
Variant value;
} key_data_cache;
+ void _time_edit_spun();
void _time_edit_entered();
void _time_edit_exited();
@@ -996,7 +997,6 @@ class AnimationMarkerKeyEditEditor : public EditorProperty {
EditorSpinSlider *spinner = nullptr;
- void _time_edit_entered();
void _time_edit_exited();
public:
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index b114977c3b..d76c324be0 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -524,7 +524,7 @@ void ConnectDialog::set_dst_node(Node *p_node) {
StringName ConnectDialog::get_dst_method_name() const {
String txt = dst_method->get_text();
if (txt.contains("(")) {
- txt = txt.left(txt.find("(")).strip_edges();
+ txt = txt.left(txt.find_char('(')).strip_edges();
}
return txt;
}
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 78dc772d9e..2273014f72 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -160,13 +160,13 @@ bool CreateDialog::_should_hide_type(const StringName &p_type) const {
String script_path = ScriptServer::get_global_class_path(p_type);
if (script_path.begins_with("res://addons/")) {
- int i = script_path.find("/", 13); // 13 is length of "res://addons/".
+ int i = script_path.find_char('/', 13); // 13 is length of "res://addons/".
while (i > -1) {
const String plugin_path = script_path.substr(0, i).path_join("plugin.cfg");
if (FileAccess::exists(plugin_path)) {
return !EditorNode::get_singleton()->is_addon_plugin_enabled(plugin_path);
}
- i = script_path.find("/", i + 1);
+ i = script_path.find_char('/', i + 1);
}
}
}
diff --git a/editor/debugger/debug_adapter/debug_adapter_parser.cpp b/editor/debugger/debug_adapter/debug_adapter_parser.cpp
index 2af629676a..904085630b 100644
--- a/editor/debugger/debug_adapter/debug_adapter_parser.cpp
+++ b/editor/debugger/debug_adapter/debug_adapter_parser.cpp
@@ -147,7 +147,7 @@ Dictionary DebugAdapterParser::req_initialize(const Dictionary &p_params) const
for (List<String>::Element *E = breakpoints.front(); E; E = E->next()) {
String breakpoint = E->get();
- String path = breakpoint.left(breakpoint.find(":", 6)); // Skip initial part of path, aka "res://"
+ String path = breakpoint.left(breakpoint.find_char(':', 6)); // Skip initial part of path, aka "res://"
int line = breakpoint.substr(path.size()).to_int();
DebugAdapterProtocol::get_singleton()->on_debug_breakpoint_toggled(path, line, true);
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index 0f948b4ed5..f06d9be78f 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -120,7 +120,7 @@ ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() {
tabs->add_child(node);
- node->set_name("Session " + itos(tabs->get_tab_count()));
+ node->set_name(vformat(TTR("Session %d"), tabs->get_tab_count()));
if (tabs->get_tab_count() > 1) {
node->clear_style();
tabs->set_tabs_visible(true);
@@ -160,9 +160,9 @@ void EditorDebuggerNode::_text_editor_stack_goto(const ScriptEditorDebugger *p_d
} else {
// If the script is built-in, it can be opened only if the scene is loaded in memory.
int i = file.find("::");
- int j = file.rfind("(", i);
+ int j = file.rfind_char('(', i);
if (j > -1) { // If the script is named, the string is "name (file)", so we need to extract the path.
- file = file.substr(j + 1, file.find(")", i) - j - 1);
+ file = file.substr(j + 1, file.find_char(')', i) - j - 1);
}
Ref<PackedScene> ps = ResourceLoader::load(file.get_slice("::", 0));
stack_script = ResourceLoader::load(file);
@@ -183,9 +183,9 @@ void EditorDebuggerNode::_text_editor_stack_clear(const ScriptEditorDebugger *p_
} else {
// If the script is built-in, it can be opened only if the scene is loaded in memory.
int i = file.find("::");
- int j = file.rfind("(", i);
+ int j = file.rfind_char('(', i);
if (j > -1) { // If the script is named, the string is "name (file)", so we need to extract the path.
- file = file.substr(j + 1, file.find(")", i) - j - 1);
+ file = file.substr(j + 1, file.find_char(')', i) - j - 1);
}
Ref<PackedScene> ps = ResourceLoader::load(file.get_slice("::", 0));
stack_script = ResourceLoader::load(file);
diff --git a/editor/debugger/editor_debugger_tree.cpp b/editor/debugger/editor_debugger_tree.cpp
index 4d67800e6e..a9e4adf674 100644
--- a/editor/debugger/editor_debugger_tree.cpp
+++ b/editor/debugger/editor_debugger_tree.cpp
@@ -382,7 +382,7 @@ void EditorDebuggerTree::_item_menu_id_pressed(int p_option) {
text = ".";
} else {
text = text.replace("/root/", "");
- int slash = text.find("/");
+ int slash = text.find_char('/');
if (slash < 0) {
text = ".";
} else {
diff --git a/editor/debugger/editor_performance_profiler.cpp b/editor/debugger/editor_performance_profiler.cpp
index 1ea9a66534..31c09c9b37 100644
--- a/editor/debugger/editor_performance_profiler.cpp
+++ b/editor/debugger/editor_performance_profiler.cpp
@@ -81,6 +81,9 @@ void EditorPerformanceProfiler::Monitor::reset() {
String EditorPerformanceProfiler::_create_label(float p_value, Performance::MonitorType p_type) {
switch (p_type) {
+ case Performance::MONITOR_TYPE_QUANTITY: {
+ return TS->format_number(itos(p_value));
+ }
case Performance::MONITOR_TYPE_MEMORY: {
return String::humanize_size(p_value);
}
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index da59450dd0..416e6f07dd 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -1062,6 +1062,7 @@ void ScriptEditorDebugger::_update_buttons_state() {
for (KeyValue<uint64_t, ThreadDebugged> &I : threads_debugged) {
threadss.push_back(&I.value);
}
+ threads->set_disabled(threadss.is_empty());
threadss.sort_custom<ThreadSort>();
threads->clear();
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index 8ba5811ffa..9ca12070fe 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -471,7 +471,7 @@ void DependencyRemoveDialog::_find_localization_remaps_of_removed_files(Vector<R
for (int j = 0; j < remap_keys.size(); j++) {
PackedStringArray remapped_files = remaps[remap_keys[j]];
for (int k = 0; k < remapped_files.size(); k++) {
- int splitter_pos = remapped_files[k].rfind(":");
+ int splitter_pos = remapped_files[k].rfind_char(':');
String res_path = remapped_files[k].substr(0, splitter_pos);
if (res_path == path) {
String locale_name = remapped_files[k].substr(splitter_pos + 1);
diff --git a/editor/directory_create_dialog.cpp b/editor/directory_create_dialog.cpp
index ee03d5a7f6..d68af88fc8 100644
--- a/editor/directory_create_dialog.cpp
+++ b/editor/directory_create_dialog.cpp
@@ -142,7 +142,7 @@ void DirectoryCreateDialog::config(const String &p_base_dir, const Callable &p_a
validation_panel->update();
if (p_mode == MODE_FILE) {
- int extension_pos = p_default_name.rfind(".");
+ int extension_pos = p_default_name.rfind_char('.');
if (extension_pos > -1) {
dir_path->select(0, extension_pos);
return;
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index 79e0c7ebd1..842c4acce0 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -908,6 +908,23 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) {
c.properties.sort();
+ List<StringName> enums;
+ Variant::get_enums_for_type(Variant::Type(i), &enums);
+
+ for (const StringName &E : enums) {
+ List<StringName> enumerations;
+ Variant::get_enumerations_for_enum(Variant::Type(i), E, &enumerations);
+
+ for (const StringName &F : enumerations) {
+ DocData::ConstantDoc constant;
+ constant.name = F;
+ constant.value = itos(Variant::get_enum_value(Variant::Type(i), E, F));
+ constant.is_value_valid = true;
+ constant.enumeration = E;
+ c.constants.push_back(constant);
+ }
+ }
+
List<StringName> constants;
Variant::get_constants_for_type(Variant::Type(i), &constants);
diff --git a/editor/editor_asset_installer.cpp b/editor/editor_asset_installer.cpp
index bce0c87452..72755e8943 100644
--- a/editor/editor_asset_installer.cpp
+++ b/editor/editor_asset_installer.cpp
@@ -130,14 +130,14 @@ void EditorAssetInstaller::open_asset(const String &p_path, bool p_autoskip_topl
// Create intermediate directories if they aren't reported by unzip.
// We are only interested in subfolders, so skip the root slash.
- int separator = source_name.find("/", 1);
+ int separator = source_name.find_char('/', 1);
while (separator != -1) {
String dir_name = source_name.substr(0, separator + 1);
if (!dir_name.is_empty() && !asset_files.has(dir_name)) {
asset_files.insert(dir_name);
}
- separator = source_name.find("/", separator + 1);
+ separator = source_name.find_char('/', separator + 1);
}
if (!source_name.is_empty() && !asset_files.has(source_name)) {
@@ -214,7 +214,7 @@ void EditorAssetInstaller::_rebuild_source_tree() {
TreeItem *parent_item;
- int separator = path.rfind("/");
+ int separator = path.rfind_char('/');
if (separator == -1) {
parent_item = root;
} else {
@@ -313,7 +313,7 @@ void EditorAssetInstaller::_rebuild_destination_tree() {
TreeItem *parent_item;
- int separator = path.rfind("/");
+ int separator = path.rfind_char('/');
if (separator == -1) {
parent_item = root;
} else {
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index cc81001efb..b5306154ba 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -1516,6 +1516,9 @@ void EditorFileSystem::_delete_internal_files(const String &p_file) {
}
da->remove(p_file + ".import");
}
+ if (FileAccess::exists(p_file + ".uid")) {
+ DirAccess::remove_absolute(p_file + ".uid");
+ }
}
int EditorFileSystem::_insert_actions_delete_files_directory(EditorFileSystemDirectory *p_dir) {
diff --git a/editor/editor_folding.cpp b/editor/editor_folding.cpp
index 18f5610655..5cb38fa875 100644
--- a/editor/editor_folding.cpp
+++ b/editor/editor_folding.cpp
@@ -249,7 +249,7 @@ void EditorFolding::_do_object_unfolds(Object *p_object, HashSet<Ref<Resource>>
}
}
} else { //path
- int last = E.name.rfind("/");
+ int last = E.name.rfind_char('/');
if (last != -1) {
bool can_revert = EditorPropertyRevert::can_property_revert(p_object, E.name);
if (can_revert) {
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 0ca1ed2d50..f0c54b9edd 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -148,7 +148,7 @@ static String _contextualize_class_specifier(const String &p_class_specifier, co
// Here equal length + begins_with from above implies p_class_specifier == p_edited_class :)
if (p_class_specifier.length() == p_edited_class.length()) {
- int rfind = p_class_specifier.rfind(".");
+ int rfind = p_class_specifier.rfind_char('.');
if (rfind == -1) { // Single identifier
return p_class_specifier;
}
@@ -234,7 +234,7 @@ void EditorHelp::_class_desc_select(const String &p_select) {
enum_class_name = "@GlobalScope";
enum_name = link;
} else {
- const int dot_pos = link.rfind(".");
+ const int dot_pos = link.rfind_char('.');
if (dot_pos >= 0) {
enum_class_name = link.left(dot_pos);
enum_name = link.substr(dot_pos + 1);
@@ -3252,7 +3252,7 @@ EditorHelpBit::HelpData EditorHelpBit::_get_property_help_data(const StringName
enum_class_name = "@GlobalScope";
enum_name = property.enumeration;
} else {
- const int dot_pos = property.enumeration.rfind(".");
+ const int dot_pos = property.enumeration.rfind_char('.');
if (dot_pos >= 0) {
enum_class_name = property.enumeration.left(dot_pos);
enum_name = property.enumeration.substr(dot_pos + 1);
@@ -3619,7 +3619,7 @@ void EditorHelpBit::_meta_clicked(const String &p_select) {
enum_class_name = "@GlobalScope";
enum_name = link;
} else {
- const int dot_pos = link.rfind(".");
+ const int dot_pos = link.rfind_char('.');
if (dot_pos >= 0) {
enum_class_name = link.left(dot_pos);
enum_name = link.substr(dot_pos + 1);
@@ -3868,7 +3868,7 @@ void EditorHelpBitTooltip::show_tooltip(EditorHelpBit *p_help_bit, Control *p_ta
EditorHelpBitTooltip *tooltip = memnew(EditorHelpBitTooltip(p_target));
p_help_bit->connect("request_hide", callable_mp(tooltip, &EditorHelpBitTooltip::_safe_queue_free));
tooltip->add_child(p_help_bit);
- p_target->get_viewport()->add_child(tooltip);
+ p_target->add_child(tooltip);
p_help_bit->update_content_height();
tooltip->popup_under_cursor();
}
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index b0c06475f8..0fc7052a2b 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -1166,7 +1166,7 @@ TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const
if (p_matching_keyword.is_empty()) {
item->set_text(0, p_doc->name);
} else {
- item->set_text(0, p_doc->name + " - " + TTR(vformat("Matches the \"%s\" keyword.", p_matching_keyword)));
+ item->set_text(0, p_doc->name + " - " + vformat(TTR("Matches the \"%s\" keyword."), p_matching_keyword));
}
if (!term.is_empty()) {
@@ -1272,7 +1272,7 @@ TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, cons
text = p_class_name + "." + p_text;
}
if (!p_matching_keyword.is_empty()) {
- text += " - " + TTR(vformat("Matches the \"%s\" keyword.", p_matching_keyword));
+ text += " - " + vformat(TTR("Matches the \"%s\" keyword."), p_matching_keyword);
}
item->set_text(0, text);
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 1c23ce8ede..1a973d7b77 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -2724,7 +2724,7 @@ void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, EditorIn
for (const EditorInspectorPlugin::AddedEditor &F : ped->added_editors) {
EditorProperty *ep = Object::cast_to<EditorProperty>(F.property_editor);
- if (ep && current_favorites.has(F.properties[0])) {
+ if (ep && !F.properties.is_empty() && current_favorites.has(F.properties[0])) {
ep->favorited = true;
favorites_vbox->add_child(F.property_editor);
} else {
@@ -3131,7 +3131,7 @@ void EditorInspector::update_tree() {
if (!array_prefix.is_empty()) {
path = path.trim_prefix(array_prefix);
- int char_index = path.find("/");
+ int char_index = path.find_char('/');
if (char_index >= 0) {
path = path.right(-char_index - 1);
} else {
@@ -3171,10 +3171,10 @@ void EditorInspector::update_tree() {
}
// Get the property label's string.
- String name_override = (path.contains("/")) ? path.substr(path.rfind("/") + 1) : path;
+ String name_override = (path.contains("/")) ? path.substr(path.rfind_char('/') + 1) : path;
String feature_tag;
{
- const int dot = name_override.find(".");
+ const int dot = name_override.find_char('.');
if (dot != -1) {
feature_tag = name_override.substr(dot);
name_override = name_override.substr(0, dot);
@@ -3189,7 +3189,7 @@ void EditorInspector::update_tree() {
const String property_label_string = EditorPropertyNameProcessor::get_singleton()->process_name(name_override, name_style, p.name, doc_name) + feature_tag;
// Remove the property from the path.
- int idx = path.rfind("/");
+ int idx = path.rfind_char('/');
if (idx > -1) {
path = path.left(idx);
} else {
@@ -3320,7 +3320,7 @@ void EditorInspector::update_tree() {
array_element_prefix = class_name_components[0];
editor_inspector_array = memnew(EditorInspectorArray(all_read_only));
- String array_label = path.contains("/") ? path.substr(path.rfind("/") + 1) : path;
+ String array_label = path.contains("/") ? path.substr(path.rfind_char('/') + 1) : path;
array_label = EditorPropertyNameProcessor::get_singleton()->process_name(property_label_string, property_name_style, p.name, doc_name);
int page = per_array_page.has(array_element_prefix) ? per_array_page[array_element_prefix] : 0;
editor_inspector_array->setup_with_move_element_function(object, array_label, array_element_prefix, page, c, use_folding);
@@ -3472,6 +3472,14 @@ void EditorInspector::update_tree() {
editors.append_array(late_editors);
+ const Node *node = Object::cast_to<Node>(object);
+
+ Vector<SceneState::PackState> sstack;
+ if (node != nullptr) {
+ const Node *es = EditorNode::get_singleton()->get_edited_scene();
+ sstack = PropertyUtils::get_node_states_stack(node, es);
+ }
+
for (int i = 0; i < editors.size(); i++) {
EditorProperty *ep = Object::cast_to<EditorProperty>(editors[i].property_editor);
const Vector<String> &properties = editors[i].properties;
@@ -3525,7 +3533,15 @@ void EditorInspector::update_tree() {
ep->set_checked(checked);
ep->set_keying(keying);
ep->set_read_only(property_read_only || all_read_only);
- ep->set_deletable(deletable_properties || p.name.begins_with("metadata/"));
+ if (p.name.begins_with("metadata/")) {
+ Variant _default = Variant();
+ if (node != nullptr) {
+ _default = PropertyUtils::get_property_default_value(node, p.name, nullptr, &sstack, false, nullptr, nullptr);
+ }
+ ep->set_deletable(_default == Variant());
+ } else {
+ ep->set_deletable(deletable_properties);
+ }
}
if (ep && ep->is_favoritable() && current_favorites.has(p.name)) {
@@ -3648,8 +3664,6 @@ void EditorInspector::update_tree() {
for (List<EditorInspectorSection *>::Element *I = sections.back(); I; I = I->prev()) {
EditorInspectorSection *section = I->get();
if (section->get_vbox()->get_child_count() == 0) {
- I = I->prev();
-
sections.erase(section);
vbox_per_path[main_vbox].erase(section->get_section());
memdelete(section);
diff --git a/editor/editor_interface.cpp b/editor/editor_interface.cpp
index 304b9d4b8c..e85258df50 100644
--- a/editor/editor_interface.cpp
+++ b/editor/editor_interface.cpp
@@ -43,6 +43,7 @@
#include "editor/gui/editor_quick_open_dialog.h"
#include "editor/gui/editor_run_bar.h"
#include "editor/gui/editor_scene_tabs.h"
+#include "editor/gui/editor_toaster.h"
#include "editor/gui/scene_tree_editor.h"
#include "editor/inspector_dock.h"
#include "editor/plugins/node_3d_editor_plugin.h"
@@ -89,6 +90,10 @@ Ref<EditorSettings> EditorInterface::get_editor_settings() const {
return EditorSettings::get_singleton();
}
+EditorToaster *EditorInterface::get_editor_toaster() const {
+ return EditorToaster::get_singleton();
+}
+
EditorUndoRedoManager *EditorInterface::get_editor_undo_redo() const {
return EditorUndoRedoManager::get_singleton();
}
@@ -280,14 +285,10 @@ void EditorInterface::set_current_feature_profile(const String &p_profile_name)
// Editor dialogs.
void EditorInterface::popup_node_selector(const Callable &p_callback, const TypedArray<StringName> &p_valid_types, Node *p_current_value) {
- // TODO: Should reuse dialog instance instead of creating a fresh one, but need to rework set_valid_types first.
- if (node_selector) {
- node_selector->disconnect(SNAME("selected"), callable_mp(this, &EditorInterface::_node_selected).bind(p_callback));
- node_selector->disconnect(SNAME("canceled"), callable_mp(this, &EditorInterface::_node_selection_canceled).bind(p_callback));
- get_base_control()->remove_child(node_selector);
- node_selector->queue_free();
+ if (!node_selector) {
+ node_selector = memnew(SceneTreeDialog);
+ get_base_control()->add_child(node_selector);
}
- node_selector = memnew(SceneTreeDialog);
Vector<StringName> valid_types;
int length = p_valid_types.size();
@@ -296,27 +297,18 @@ void EditorInterface::popup_node_selector(const Callable &p_callback, const Type
valid_types.write[i] = p_valid_types[i];
}
node_selector->set_valid_types(valid_types);
-
- get_base_control()->add_child(node_selector);
-
node_selector->popup_scenetree_dialog(p_current_value);
- const Callable selected_callback = callable_mp(this, &EditorInterface::_node_selected).bind(p_callback);
- node_selector->connect(SNAME("selected"), selected_callback, CONNECT_DEFERRED);
-
- const Callable canceled_callback = callable_mp(this, &EditorInterface::_node_selection_canceled).bind(p_callback);
- node_selector->connect(SNAME("canceled"), canceled_callback, CONNECT_DEFERRED);
+ const Callable callback = callable_mp(this, &EditorInterface::_node_selected);
+ node_selector->connect(SNAME("selected"), callback.bind(p_callback), CONNECT_DEFERRED);
+ node_selector->connect(SNAME("canceled"), callback.bind(NodePath(), p_callback), CONNECT_DEFERRED);
}
void EditorInterface::popup_property_selector(Object *p_object, const Callable &p_callback, const PackedInt32Array &p_type_filter, const String &p_current_value) {
- // TODO: Should reuse dialog instance instead of creating a fresh one, but need to rework set_type_filter first.
- if (property_selector) {
- property_selector->disconnect(SNAME("selected"), callable_mp(this, &EditorInterface::_property_selected).bind(p_callback));
- property_selector->disconnect(SNAME("canceled"), callable_mp(this, &EditorInterface::_property_selection_canceled).bind(p_callback));
- get_base_control()->remove_child(property_selector);
- property_selector->queue_free();
+ if (!property_selector) {
+ property_selector = memnew(PropertySelector);
+ get_base_control()->add_child(property_selector);
}
- property_selector = memnew(PropertySelector);
Vector<Variant::Type> type_filter;
int length = p_type_filter.size();
@@ -325,16 +317,11 @@ void EditorInterface::popup_property_selector(Object *p_object, const Callable &
type_filter.write[i] = (Variant::Type)p_type_filter[i];
}
property_selector->set_type_filter(type_filter);
-
- get_base_control()->add_child(property_selector);
-
property_selector->select_property_from_instance(p_object, p_current_value);
- const Callable selected_callback = callable_mp(this, &EditorInterface::_property_selected).bind(p_callback);
- property_selector->connect(SNAME("selected"), selected_callback, CONNECT_DEFERRED);
-
- const Callable canceled_callback = callable_mp(this, &EditorInterface::_property_selection_canceled).bind(p_callback);
- property_selector->connect(SNAME("canceled"), canceled_callback, CONNECT_DEFERRED);
+ const Callable callback = callable_mp(this, &EditorInterface::_property_selected);
+ property_selector->connect(SNAME("selected"), callback.bind(p_callback), CONNECT_DEFERRED);
+ property_selector->connect(SNAME("canceled"), callback.bind(String(), p_callback), CONNECT_DEFERRED);
}
void EditorInterface::popup_method_selector(Object *p_object, const Callable &p_callback, const String &p_current_value) {
@@ -369,20 +356,28 @@ void EditorInterface::popup_quick_open(const Callable &p_callback, const TypedAr
}
void EditorInterface::_node_selected(const NodePath &p_node_path, const Callable &p_callback) {
- const NodePath path = get_edited_scene_root()->get_path().rel_path_to(p_node_path);
- _call_dialog_callback(p_callback, path, "node selected");
-}
+ const Callable callback = callable_mp(this, &EditorInterface::_node_selected);
+ node_selector->disconnect(SNAME("selected"), callback);
+ node_selector->disconnect(SNAME("canceled"), callback);
-void EditorInterface::_node_selection_canceled(const Callable &p_callback) {
- _call_dialog_callback(p_callback, NodePath(), "node selection canceled");
+ if (p_node_path.is_empty()) {
+ _call_dialog_callback(p_callback, NodePath(), "node selection canceled");
+ } else {
+ const NodePath path = get_edited_scene_root()->get_path().rel_path_to(p_node_path);
+ _call_dialog_callback(p_callback, path, "node selected");
+ }
}
void EditorInterface::_property_selected(const String &p_property_name, const Callable &p_callback) {
- _call_dialog_callback(p_callback, NodePath(p_property_name).get_as_property_path(), "property selected");
-}
+ const Callable callback = callable_mp(this, &EditorInterface::_property_selected);
+ property_selector->disconnect(SNAME("selected"), callback);
+ property_selector->disconnect(SNAME("canceled"), callback);
-void EditorInterface::_property_selection_canceled(const Callable &p_callback) {
- _call_dialog_callback(p_callback, NodePath(), "property selection canceled");
+ if (p_property_name.is_empty()) {
+ _call_dialog_callback(p_callback, NodePath(p_property_name).get_as_property_path(), "property selection canceled");
+ } else {
+ _call_dialog_callback(p_callback, NodePath(p_property_name).get_as_property_path(), "property selected");
+ }
}
void EditorInterface::_method_selected(const String &p_method_name, const Callable &p_callback) {
@@ -581,6 +576,7 @@ void EditorInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_resource_previewer"), &EditorInterface::get_resource_previewer);
ClassDB::bind_method(D_METHOD("get_selection"), &EditorInterface::get_selection);
ClassDB::bind_method(D_METHOD("get_editor_settings"), &EditorInterface::get_editor_settings);
+ ClassDB::bind_method(D_METHOD("get_editor_toaster"), &EditorInterface::get_editor_toaster);
ClassDB::bind_method(D_METHOD("get_editor_undo_redo"), &EditorInterface::get_editor_undo_redo);
ClassDB::bind_method(D_METHOD("make_mesh_previews", "meshes", "preview_size"), &EditorInterface::_make_mesh_previews);
diff --git a/editor/editor_interface.h b/editor/editor_interface.h
index c1032bf9b6..2ae77331b1 100644
--- a/editor/editor_interface.h
+++ b/editor/editor_interface.h
@@ -45,6 +45,7 @@ class EditorPlugin;
class EditorResourcePreview;
class EditorSelection;
class EditorSettings;
+class EditorToaster;
class EditorUndoRedoManager;
class FileSystemDock;
class Mesh;
@@ -70,9 +71,7 @@ class EditorInterface : public Object {
SceneTreeDialog *node_selector = nullptr;
void _node_selected(const NodePath &p_node_paths, const Callable &p_callback);
- void _node_selection_canceled(const Callable &p_callback);
void _property_selected(const String &p_property_name, const Callable &p_callback);
- void _property_selection_canceled(const Callable &p_callback);
void _method_selected(const String &p_property_name, const Callable &p_callback);
void _quick_open(const String &p_file_path, const Callable &p_callback);
void _call_dialog_callback(const Callable &p_callback, const Variant &p_selected, const String &p_context);
@@ -104,6 +103,7 @@ public:
EditorResourcePreview *get_resource_previewer() const;
EditorSelection *get_selection() const;
Ref<EditorSettings> get_editor_settings() const;
+ EditorToaster *get_editor_toaster() const;
EditorUndoRedoManager *get_editor_undo_redo() const;
Vector<Ref<Texture2D>> make_mesh_previews(const Vector<Ref<Mesh>> &p_meshes, Vector<Transform3D> *p_transforms, int p_preview_size);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index f8e23ecc9d..222696a608 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -253,8 +253,8 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto
// append that to yield "folder/foo.tscn".
if (difference > 0) {
String parent = full_path.substr(0, difference);
- int slash_idx = parent.rfind("/");
- slash_idx = parent.rfind("/", slash_idx - 1);
+ int slash_idx = parent.rfind_char('/');
+ slash_idx = parent.rfind_char('/', slash_idx - 1);
parent = (slash_idx >= 0 && parent.length() > 1) ? parent.substr(slash_idx + 1) : parent;
r_filenames.write[set_idx] = parent + r_filenames[set_idx];
}
@@ -1454,6 +1454,16 @@ void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String
file->popup_file_dialog();
}
+void EditorNode::ensure_uid_file(const String &p_new_resource_path) {
+ if (ResourceLoader::exists(p_new_resource_path) && !ResourceLoader::has_custom_uid_support(p_new_resource_path) && !FileAccess::exists(p_new_resource_path + ".uid")) {
+ Ref<FileAccess> f = FileAccess::open(p_new_resource_path + ".uid", FileAccess::WRITE);
+ if (f.is_valid()) {
+ const ResourceUID::ID id = ResourceUID::get_singleton()->create_id();
+ f->store_line(ResourceUID::get_singleton()->id_to_text(id));
+ }
+ }
+}
+
void EditorNode::_menu_option(int p_option) {
_menu_option_confirm(p_option, false);
}
@@ -2173,6 +2183,12 @@ void EditorNode::_dialog_action(String p_file) {
case RESOURCE_SAVE_AS: {
ERR_FAIL_COND(saving_resource.is_null());
save_resource_in_path(saving_resource, p_file);
+
+ if (current_menu_option == RESOURCE_SAVE_AS) {
+ // Create .uid file when making new Resource.
+ ensure_uid_file(p_file);
+ }
+
saving_resource = Ref<Resource>();
ObjectID current_id = editor_history.get_current();
Object *current_obj = current_id.is_valid() ? ObjectDB::get_instance(current_id) : nullptr;
@@ -5174,7 +5190,8 @@ void EditorNode::show_accept(const String &p_text, const String &p_title) {
_close_save_scene_progress();
accept->set_ok_button_text(p_title);
accept->set_text(p_text);
- EditorInterface::get_singleton()->popup_dialog_centered(accept);
+ accept->reset_size();
+ EditorInterface::get_singleton()->popup_dialog_centered_clamped(accept, Size2i(), 0.0);
}
}
@@ -5184,7 +5201,8 @@ void EditorNode::show_save_accept(const String &p_text, const String &p_title) {
_close_save_scene_progress();
save_accept->set_ok_button_text(p_title);
save_accept->set_text(p_text);
- EditorInterface::get_singleton()->popup_dialog_centered(save_accept);
+ save_accept->reset_size();
+ EditorInterface::get_singleton()->popup_dialog_centered_clamped(save_accept, Size2i(), 0.0);
}
}
@@ -5193,7 +5211,8 @@ void EditorNode::show_warning(const String &p_text, const String &p_title) {
_close_save_scene_progress();
warning->set_text(p_text);
warning->set_title(p_title);
- EditorInterface::get_singleton()->popup_dialog_centered(warning);
+ warning->reset_size();
+ EditorInterface::get_singleton()->popup_dialog_centered_clamped(warning, Size2i(), 0.0);
} else {
WARN_PRINT(p_title + " " + p_text);
}
@@ -7690,24 +7709,28 @@ EditorNode::EditorNode() {
disk_changed = memnew(ConfirmationDialog);
{
- disk_changed->set_title(TTR("Files have been modified on disk"));
+ disk_changed->set_title(TTR("Files have been modified outside Godot"));
VBoxContainer *vbc = memnew(VBoxContainer);
disk_changed->add_child(vbc);
Label *dl = memnew(Label);
- dl->set_text(TTR("The following files are newer on disk.\nWhat action should be taken?"));
+ dl->set_text(TTR("The following files are newer on disk:"));
vbc->add_child(dl);
disk_changed_list = memnew(Tree);
vbc->add_child(disk_changed_list);
disk_changed_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ Label *what_action_label = memnew(Label);
+ what_action_label->set_text(TTR("What action should be taken?"));
+ vbc->add_child(what_action_label);
+
disk_changed->connect(SceneStringName(confirmed), callable_mp(this, &EditorNode::_reload_modified_scenes));
disk_changed->connect(SceneStringName(confirmed), callable_mp(this, &EditorNode::_reload_project_settings));
- disk_changed->set_ok_button_text(TTR("Discard local changes and reload"));
+ disk_changed->set_ok_button_text(TTR("Reload from disk"));
- disk_changed->add_button(TTR("Keep local changes and overwrite"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave");
+ disk_changed->add_button(TTR("Ignore external changes"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave");
disk_changed->connect("custom_action", callable_mp(this, &EditorNode::_resave_scenes));
}
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 49c1699c28..4a283983c8 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -747,6 +747,7 @@ public:
void save_resource_in_path(const Ref<Resource> &p_resource, const String &p_path);
void save_resource(const Ref<Resource> &p_resource);
void save_resource_as(const Ref<Resource> &p_resource, const String &p_at_path = String());
+ void ensure_uid_file(const String &p_new_resource_path);
void show_about() { _menu_option_confirm(HELP_ABOUT, false); }
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index bdb5ed2ed9..b600e49b61 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -52,6 +52,7 @@
#include "scene/3d/fog_volume.h"
#include "scene/3d/gpu_particles_3d.h"
#include "scene/gui/color_picker.h"
+#include "scene/gui/grid_container.h"
#include "scene/main/window.h"
#include "scene/resources/font.h"
#include "scene/resources/mesh.h"
@@ -463,10 +464,12 @@ void EditorPropertyPath::_set_read_only(bool p_read_only) {
void EditorPropertyPath::_path_selected(const String &p_path) {
String full_path = p_path;
- ResourceUID::ID id = ResourceLoader::get_resource_uid(full_path);
- if (id != ResourceUID::INVALID_ID) {
- full_path = ResourceUID::get_singleton()->id_to_text(id);
+ if (!global) {
+ const ResourceUID::ID id = ResourceLoader::get_resource_uid(full_path);
+ if (id != ResourceUID::INVALID_ID) {
+ full_path = ResourceUID::get_singleton()->id_to_text(id);
+ }
}
emit_changed(get_edited_property(), full_path);
@@ -476,7 +479,7 @@ void EditorPropertyPath::_path_selected(const String &p_path) {
String EditorPropertyPath::_get_path_text() {
String full_path = get_edited_property_value();
if (full_path.begins_with("uid://")) {
- full_path = ResourceUID::get_singleton()->get_id_path(ResourceUID::get_singleton()->text_to_id(full_path));
+ full_path = ResourceUID::uid_to_path(full_path);
}
return full_path;
@@ -2643,7 +2646,7 @@ EditorPropertyColor::EditorPropertyColor() {
add_child(picker);
picker->set_flat(true);
picker->connect("color_changed", callable_mp(this, &EditorPropertyColor::_color_changed));
- picker->connect("popup_closed", callable_mp(this, &EditorPropertyColor::_popup_closed));
+ picker->connect("popup_closed", callable_mp(this, &EditorPropertyColor::_popup_closed), CONNECT_DEFERRED);
picker->get_popup()->connect("about_to_popup", callable_mp(EditorNode::get_singleton(), &EditorNode::setup_color_picker).bind(picker->get_picker()));
picker->get_popup()->connect("about_to_popup", callable_mp(this, &EditorPropertyColor::_picker_opening));
}
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index ba6b42f8f5..3cc3a0f7c2 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -740,10 +740,10 @@ void EditorPropertyArray::setup(Variant::Type p_array_type, const String &p_hint
// The format of p_hint_string is:
// subType/subTypeHint:nextSubtype ... etc.
if (!p_hint_string.is_empty()) {
- int hint_subtype_separator = p_hint_string.find(":");
+ int hint_subtype_separator = p_hint_string.find_char(':');
if (hint_subtype_separator >= 0) {
String subtype_string = p_hint_string.substr(0, hint_subtype_separator);
- int slash_pos = subtype_string.find("/");
+ int slash_pos = subtype_string.find_char('/');
if (slash_pos >= 0) {
subtype_hint = PropertyHint(subtype_string.substr(slash_pos + 1, subtype_string.size() - slash_pos - 1).to_int());
subtype_string = subtype_string.substr(0, slash_pos);
@@ -1006,10 +1006,10 @@ void EditorPropertyDictionary::setup(PropertyHint p_hint, const String &p_hint_s
PackedStringArray types = p_hint_string.split(";");
if (types.size() > 0 && !types[0].is_empty()) {
String key = types[0];
- int hint_key_subtype_separator = key.find(":");
+ int hint_key_subtype_separator = key.find_char(':');
if (hint_key_subtype_separator >= 0) {
String key_subtype_string = key.substr(0, hint_key_subtype_separator);
- int slash_pos = key_subtype_string.find("/");
+ int slash_pos = key_subtype_string.find_char('/');
if (slash_pos >= 0) {
key_subtype_hint = PropertyHint(key_subtype_string.substr(slash_pos + 1, key_subtype_string.size() - slash_pos - 1).to_int());
key_subtype_string = key_subtype_string.substr(0, slash_pos);
@@ -1025,10 +1025,10 @@ void EditorPropertyDictionary::setup(PropertyHint p_hint, const String &p_hint_s
}
if (types.size() > 1 && !types[1].is_empty()) {
String value = types[1];
- int hint_value_subtype_separator = value.find(":");
+ int hint_value_subtype_separator = value.find_char(':');
if (hint_value_subtype_separator >= 0) {
String value_subtype_string = value.substr(0, hint_value_subtype_separator);
- int slash_pos = value_subtype_string.find("/");
+ int slash_pos = value_subtype_string.find_char('/');
if (slash_pos >= 0) {
value_subtype_hint = PropertyHint(value_subtype_string.substr(slash_pos + 1, value_subtype_string.size() - slash_pos - 1).to_int());
value_subtype_string = value_subtype_string.substr(0, slash_pos);
@@ -1173,6 +1173,11 @@ void EditorPropertyDictionary::update_property() {
new_prop->set_h_size_flags(SIZE_EXPAND_FILL);
new_prop->set_read_only(is_read_only());
slot.set_prop(new_prop);
+ } else if (slot.index != EditorPropertyDictionaryObject::NEW_KEY_INDEX && slot.index != EditorPropertyDictionaryObject::NEW_VALUE_INDEX) {
+ Variant key = dict.get_key_at_index(slot.index);
+ String cs = key.get_construct_string();
+ slot.prop->set_label(cs);
+ slot.prop->set_tooltip_text(cs);
}
// We need to grab the focus of the property that is being changed, even if the type didn't actually changed.
@@ -1200,7 +1205,8 @@ void EditorPropertyDictionary::update_property() {
void EditorPropertyDictionary::_remove_pressed(int p_slot_index) {
Dictionary dict = object->get_dict().duplicate();
- dict.erase(dict.get_key_at_index(p_slot_index));
+ int index = slots[p_slot_index].index;
+ dict.erase(dict.get_key_at_index(index));
emit_changed(get_edited_property(), dict);
}
diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp
index 27cbb9810c..d88cc4d5fa 100644
--- a/editor/editor_sectioned_inspector.cpp
+++ b/editor/editor_sectioned_inspector.cpp
@@ -96,7 +96,7 @@ class SectionedInspectorFilter : public Object {
List<PropertyInfo> pinfo;
edited->get_property_list(&pinfo);
for (PropertyInfo &pi : pinfo) {
- int sp = pi.name.find("/");
+ int sp = pi.name.find_char('/');
if (pi.name == "resource_path" || pi.name == "resource_name" || pi.name == "resource_local_to_scene" || pi.name.begins_with("script/") || pi.name.begins_with("_global_script")) { //skip resource stuff
continue;
@@ -255,7 +255,7 @@ void SectionedInspector::update_category_list() {
continue;
}
- int sp = pi.name.find("/");
+ int sp = pi.name.find_char('/');
if (sp == -1) {
pi.name = "global/" + pi.name;
}
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 44690f81f0..b0d1c3e6bb 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -715,6 +715,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("text_editor/script_list/sort_members_outline_alphabetically", false, true);
_initial_set("text_editor/script_list/script_temperature_enabled", true);
_initial_set("text_editor/script_list/script_temperature_history_size", 15);
+ _initial_set("text_editor/script_list/highlight_scene_scripts", true);
_initial_set("text_editor/script_list/group_help_pages", true);
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/script_list/sort_scripts_by", 0, "Name,Path,None");
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/script_list/list_script_names_as", 0, "Name,Parent Directory And Name,Full Path");
diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp
index d6742c9b55..8989b9cf9b 100644
--- a/editor/editor_settings_dialog.cpp
+++ b/editor/editor_settings_dialog.cpp
@@ -106,8 +106,8 @@ void EditorSettingsDialog::update_navigation_preset() {
orbit_mod_key_2 = InputEventKey::create_reference(Key::NONE);
pan_mod_key_1 = InputEventKey::create_reference(Key::SHIFT);
pan_mod_key_2 = InputEventKey::create_reference(Key::NONE);
- zoom_mod_key_1 = InputEventKey::create_reference(Key::SHIFT);
- zoom_mod_key_2 = InputEventKey::create_reference(Key::CTRL);
+ zoom_mod_key_1 = InputEventKey::create_reference(Key::CTRL);
+ zoom_mod_key_2 = InputEventKey::create_reference(Key::NONE);
} else if (nav_scheme == Node3DEditorViewport::NAVIGATION_MAYA) {
set_preset = true;
set_orbit_mouse_button = Node3DEditorViewport::NAVIGATION_LEFT_MOUSE;
diff --git a/editor/editor_translation_parser.cpp b/editor/editor_translation_parser.cpp
index 8a77ce4a82..d12bbc1af2 100644
--- a/editor/editor_translation_parser.cpp
+++ b/editor/editor_translation_parser.cpp
@@ -31,7 +31,6 @@
#include "editor_translation_parser.h"
#include "core/error/error_macros.h"
-#include "core/io/file_access.h"
#include "core/object/script_language.h"
#include "core/templates/hash_set.h"
@@ -65,6 +64,21 @@ Error EditorTranslationParserPlugin::parse_file(const String &p_path, Vector<Str
}
}
+void EditorTranslationParserPlugin::get_comments(Vector<String> *r_ids_comment, Vector<String> *r_ids_ctx_plural_comment) {
+ TypedArray<String> ids_comment;
+ TypedArray<String> ids_ctx_plural_comment;
+
+ if (GDVIRTUAL_CALL(_get_comments, ids_comment, ids_ctx_plural_comment)) {
+ for (int i = 0; i < ids_comment.size(); i++) {
+ r_ids_comment->append(ids_comment[i]);
+ }
+
+ for (int i = 0; i < ids_ctx_plural_comment.size(); i++) {
+ r_ids_ctx_plural_comment->append(ids_ctx_plural_comment[i]);
+ }
+ }
+}
+
void EditorTranslationParserPlugin::get_recognized_extensions(List<String> *r_extensions) const {
Vector<String> extensions;
if (GDVIRTUAL_CALL(_get_recognized_extensions, extensions)) {
@@ -78,6 +92,7 @@ void EditorTranslationParserPlugin::get_recognized_extensions(List<String> *r_ex
void EditorTranslationParserPlugin::_bind_methods() {
GDVIRTUAL_BIND(_parse_file, "path", "msgids", "msgids_context_plural");
+ GDVIRTUAL_BIND(_get_comments, "msgids_comment", "msgids_context_plural_comment");
GDVIRTUAL_BIND(_get_recognized_extensions);
}
diff --git a/editor/editor_translation_parser.h b/editor/editor_translation_parser.h
index 78dc726c52..20c8ed7939 100644
--- a/editor/editor_translation_parser.h
+++ b/editor/editor_translation_parser.h
@@ -43,10 +43,12 @@ protected:
static void _bind_methods();
GDVIRTUAL3(_parse_file, String, TypedArray<String>, TypedArray<Array>)
+ GDVIRTUAL2(_get_comments, TypedArray<String>, TypedArray<String>)
GDVIRTUAL0RC(Vector<String>, _get_recognized_extensions)
public:
virtual Error parse_file(const String &p_path, Vector<String> *r_ids, Vector<Vector<String>> *r_ids_ctx_plural);
+ virtual void get_comments(Vector<String> *r_ids_comment, Vector<String> *r_ids_ctx_plural_comment);
virtual void get_recognized_extensions(List<String> *r_extensions) const;
};
diff --git a/editor/engine_update_label.cpp b/editor/engine_update_label.cpp
index facbfc7c6b..0d40181257 100644
--- a/editor/engine_update_label.cpp
+++ b/editor/engine_update_label.cpp
@@ -240,8 +240,8 @@ EngineUpdateLabel::VersionType EngineUpdateLabel::_get_version_type(const String
}
String EngineUpdateLabel::_extract_sub_string(const String &p_line) const {
- int j = p_line.find("\"") + 1;
- return p_line.substr(j, p_line.find("\"", j) - j);
+ int j = p_line.find_char('"') + 1;
+ return p_line.substr(j, p_line.find_char('"', j) - j);
}
void EngineUpdateLabel::_notification(int p_what) {
diff --git a/editor/event_listener_line_edit.cpp b/editor/event_listener_line_edit.cpp
index 8fde728027..a6b30233fc 100644
--- a/editor/event_listener_line_edit.cpp
+++ b/editor/event_listener_line_edit.cpp
@@ -121,7 +121,7 @@ String EventListenerLineEdit::get_event_text(const Ref<InputEvent> &p_event, boo
}
String EventListenerLineEdit::get_device_string(int p_device) {
- if (p_device == InputEvent::DEVICE_ID_ALL_DEVICES) {
+ if (p_device == InputMap::ALL_DEVICES) {
return TTR("All Devices");
}
return TTR("Device") + " " + itos(p_device);
diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp
index 6ca83c5e25..cddc8173cb 100644
--- a/editor/export/editor_export.cpp
+++ b/editor/export/editor_export.cpp
@@ -87,6 +87,8 @@ void EditorExport::_save() {
config->set_value(section, "encryption_include_filters", preset->get_enc_in_filter());
config->set_value(section, "encryption_exclude_filters", preset->get_enc_ex_filter());
+ config->set_value(section, "seed", preset->get_seed());
+
config->set_value(section, "encrypt_pck", preset->get_enc_pck());
config->set_value(section, "encrypt_directory", preset->get_enc_directory());
config->set_value(section, "script_export_mode", preset->get_script_export_mode());
@@ -307,6 +309,9 @@ void EditorExport::load_config() {
preset->set_script_export_mode(config->get_value(section, "script_export_mode", EditorExportPreset::MODE_SCRIPT_BINARY_TOKENS_COMPRESSED));
preset->set_patches(config->get_value(section, "patches", Vector<String>()));
+ if (config->has_section_key(section, "seed")) {
+ preset->set_seed(config->get_value(section, "seed"));
+ }
if (config->has_section_key(section, "encrypt_pck")) {
preset->set_enc_pck(config->get_value(section, "encrypt_pck"));
}
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index 8b8fafcd32..27216c2399 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -216,7 +216,7 @@ void EditorExportPlatform::_unload_patches() {
PackedData::get_singleton()->clear();
}
-Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
+Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed) {
ERR_FAIL_COND_V_MSG(p_total < 1, ERR_PARAMETER_RANGE_ERROR, "Must select at least one file to export.");
PackData *pd = (PackData *)p_userdata;
@@ -247,10 +247,27 @@ Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_pa
Ref<FileAccess> ftmp = pd->f;
if (sd.encrypted) {
+ Vector<uint8_t> iv;
+ if (p_seed != 0) {
+ uint64_t seed = p_seed;
+
+ const uint8_t *ptr = p_data.ptr();
+ int64_t len = p_data.size();
+ for (int64_t i = 0; i < len; i++) {
+ seed = ((seed << 5) + seed) ^ ptr[i];
+ }
+
+ RandomPCG rng = RandomPCG(seed, RandomPCG::DEFAULT_INC);
+ iv.resize(16);
+ for (int i = 0; i < 16; i++) {
+ iv.write[i] = rng.rand() % 256;
+ }
+ }
+
fae.instantiate();
ERR_FAIL_COND_V(fae.is_null(), ERR_SKIP);
- Error err = fae->open_and_parse(ftmp, p_key, FileAccessEncrypted::MODE_WRITE_AES256, false);
+ Error err = fae->open_and_parse(ftmp, p_key, FileAccessEncrypted::MODE_WRITE_AES256, false, iv);
ERR_FAIL_COND_V(err != OK, ERR_SKIP);
ftmp = fae;
}
@@ -288,15 +305,15 @@ Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_pa
return OK;
}
-Error EditorExportPlatform::_save_pack_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
+Error EditorExportPlatform::_save_pack_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed) {
if (_check_hash(PackedData::get_singleton()->get_file_hash(p_path), p_data)) {
return OK;
}
- return _save_pack_file(p_userdata, p_path, p_data, p_file, p_total, p_enc_in_filters, p_enc_ex_filters, p_key);
+ return _save_pack_file(p_userdata, p_path, p_data, p_file, p_total, p_enc_in_filters, p_enc_ex_filters, p_key, p_seed);
}
-Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
+Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed) {
ERR_FAIL_COND_V_MSG(p_total < 1, ERR_PARAMETER_RANGE_ERROR, "Must select at least one file to export.");
String path = p_path.replace_first("res://", "");
@@ -328,12 +345,12 @@ Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_pat
return OK;
}
-Error EditorExportPlatform::_save_zip_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
+Error EditorExportPlatform::_save_zip_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed) {
if (_check_hash(PackedData::get_singleton()->get_file_hash(p_path), p_data)) {
return OK;
}
- return _save_zip_file(p_userdata, p_path, p_data, p_file, p_total, p_enc_in_filters, p_enc_ex_filters, p_key);
+ return _save_zip_file(p_userdata, p_path, p_data, p_file, p_total, p_enc_in_filters, p_enc_ex_filters, p_key, p_seed);
}
Ref<ImageTexture> EditorExportPlatform::get_option_icon(int p_index) const {
@@ -932,7 +949,7 @@ Vector<String> EditorExportPlatform::get_forced_export_files() {
return files;
}
-Error EditorExportPlatform::_script_save_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
+Error EditorExportPlatform::_script_save_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed) {
Callable cb = ((ScriptCallbackData *)p_userdata)->file_cb;
ERR_FAIL_COND_V(!cb.is_valid(), FAILED);
@@ -1043,8 +1060,10 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
Vector<String> enc_in_filters;
Vector<String> enc_ex_filters;
Vector<uint8_t> key;
+ uint64_t seed = 0;
if (enc_pck) {
+ seed = p_preset->get_seed();
Vector<String> enc_in_split = p_preset->get_enc_in_filter().split(",");
for (int i = 0; i < enc_in_split.size(); i++) {
String f = enc_in_split[i].strip_edges();
@@ -1116,7 +1135,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
}
}
for (int j = 0; j < export_plugins[i]->extra_files.size(); j++) {
- err = p_save_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, 0, paths.size(), enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, 0, paths.size(), enc_in_filters, enc_ex_filters, key, seed);
if (err != OK) {
return err;
}
@@ -1234,7 +1253,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
}
for (int j = 0; j < export_plugins[i]->extra_files.size(); j++) {
- err = p_save_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, idx, total, enc_in_filters, enc_ex_filters, key, seed);
if (err != OK) {
return err;
}
@@ -1266,7 +1285,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
if (importer_type == "keep") {
// Just keep file as-is.
Vector<uint8_t> array = FileAccess::get_file_as_bytes(path);
- err = p_save_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key, seed);
if (err != OK) {
return err;
@@ -1309,13 +1328,13 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
sarr.resize(cs.size());
memcpy(sarr.ptrw(), cs.ptr(), sarr.size());
- err = p_save_func(p_udata, path + ".import", sarr, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, path + ".import", sarr, idx, total, enc_in_filters, enc_ex_filters, key, seed);
if (err != OK) {
return err;
}
// Now actual remapped file:
sarr = FileAccess::get_file_as_bytes(export_path);
- err = p_save_func(p_udata, export_path, sarr, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, export_path, sarr, idx, total, enc_in_filters, enc_ex_filters, key, seed);
if (err != OK) {
return err;
}
@@ -1345,14 +1364,14 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
if (remap == "path") {
String remapped_path = config->get_value("remap", remap);
Vector<uint8_t> array = FileAccess::get_file_as_bytes(remapped_path);
- err = p_save_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key, seed);
} else if (remap.begins_with("path.")) {
String feature = remap.get_slice(".", 1);
if (remap_features.has(feature)) {
String remapped_path = config->get_value("remap", remap);
Vector<uint8_t> array = FileAccess::get_file_as_bytes(remapped_path);
- err = p_save_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key, seed);
} else {
// Remove paths if feature not enabled.
config->erase_section_key("remap", remap);
@@ -1378,7 +1397,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
sarr.resize(cs.size());
memcpy(sarr.ptrw(), cs.ptr(), sarr.size());
- err = p_save_func(p_udata, path + ".import", sarr, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, path + ".import", sarr, idx, total, enc_in_filters, enc_ex_filters, key, seed);
if (err != OK) {
return err;
@@ -1399,7 +1418,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
}
Vector<uint8_t> array = FileAccess::get_file_as_bytes(export_path);
- err = p_save_func(p_udata, export_path, array, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, export_path, array, idx, total, enc_in_filters, enc_ex_filters, key, seed);
if (err != OK) {
return err;
}
@@ -1463,7 +1482,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
new_file.write[j] = utf8[j];
}
- err = p_save_func(p_udata, from + ".remap", new_file, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, from + ".remap", new_file, idx, total, enc_in_filters, enc_ex_filters, key, seed);
if (err != OK) {
return err;
}
@@ -1476,8 +1495,16 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
Vector<String> forced_export = get_forced_export_files();
for (int i = 0; i < forced_export.size(); i++) {
- Vector<uint8_t> array = FileAccess::get_file_as_bytes(forced_export[i]);
- err = p_save_func(p_udata, forced_export[i], array, idx, total, enc_in_filters, enc_ex_filters, key);
+ Vector<uint8_t> array;
+ if (GDExtension::get_extension_list_config_file() == forced_export[i]) {
+ array = _filter_extension_list_config_file(forced_export[i], paths);
+ if (array.size() == 0) {
+ continue;
+ }
+ } else {
+ array = FileAccess::get_file_as_bytes(forced_export[i]);
+ }
+ err = p_save_func(p_udata, forced_export[i], array, idx, total, enc_in_filters, enc_ex_filters, key, seed);
if (err != OK) {
return err;
}
@@ -1489,7 +1516,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
Vector<uint8_t> data = FileAccess::get_file_as_bytes(engine_cfb);
DirAccess::remove_file_or_error(engine_cfb);
- err = p_save_func(p_udata, "res://" + config_file, data, idx, total, enc_in_filters, enc_ex_filters, key);
+ err = p_save_func(p_udata, "res://" + config_file, data, idx, total, enc_in_filters, enc_ex_filters, key, seed);
if (err != OK) {
return err;
}
@@ -1515,6 +1542,22 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
return OK;
}
+Vector<uint8_t> EditorExportPlatform::_filter_extension_list_config_file(const String &p_config_path, const HashSet<String> &p_paths) {
+ Ref<FileAccess> f = FileAccess::open(p_config_path, FileAccess::READ);
+ if (f.is_null()) {
+ ERR_FAIL_V_MSG(Vector<uint8_t>(), "Can't open file from path '" + String(p_config_path) + "'.");
+ }
+ Vector<uint8_t> data;
+ while (!f->eof_reached()) {
+ String l = f->get_line().strip_edges();
+ if (p_paths.has(l)) {
+ data.append_array(l.to_utf8_buffer());
+ data.append('\n');
+ }
+ }
+ return data;
+}
+
Error EditorExportPlatform::_pack_add_shared_object(void *p_userdata, const SharedObject &p_so) {
PackData *pack_data = (PackData *)p_userdata;
if (pack_data->so_files) {
@@ -1872,6 +1915,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
Ref<FileAccess> fhead = f;
if (enc_pck && enc_directory) {
+ uint64_t seed = p_preset->get_seed();
String script_key = _get_script_encryption_key(p_preset);
Vector<uint8_t> key;
key.resize(32);
@@ -1906,7 +1950,27 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
return ERR_CANT_CREATE;
}
- err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_WRITE_AES256, false);
+ Vector<uint8_t> iv;
+ if (seed != 0) {
+ for (int i = 0; i < pd.file_ofs.size(); i++) {
+ for (int64_t j = 0; j < pd.file_ofs[i].path_utf8.length(); j++) {
+ seed = ((seed << 5) + seed) ^ pd.file_ofs[i].path_utf8.get_data()[j];
+ }
+ for (int64_t j = 0; j < pd.file_ofs[i].md5.size(); j++) {
+ seed = ((seed << 5) + seed) ^ pd.file_ofs[i].md5[j];
+ }
+ seed = ((seed << 5) + seed) ^ pd.file_ofs[i].ofs;
+ seed = ((seed << 5) + seed) ^ pd.file_ofs[i].size;
+ }
+
+ RandomPCG rng = RandomPCG(seed, RandomPCG::DEFAULT_INC);
+ iv.resize(16);
+ for (int i = 0; i < 16; i++) {
+ iv.write[i] = rng.rand() % 256;
+ }
+ }
+
+ err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_WRITE_AES256, false, iv);
if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Save PCK"), TTR("Can't open encrypted file to write."));
return ERR_CANT_CREATE;
diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h
index 919fb2915a..a33bdce72a 100644
--- a/editor/export/editor_export_platform.h
+++ b/editor/export/editor_export_platform.h
@@ -53,7 +53,7 @@ protected:
static void _bind_methods();
public:
- typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
+ typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed);
typedef Error (*EditorExportRemoveFunction)(void *p_userdata, const String &p_path);
typedef Error (*EditorExportSaveSharedObject)(void *p_userdata, const SharedObject &p_so);
@@ -114,14 +114,14 @@ private:
static bool _check_hash(const uint8_t *p_hash, const Vector<uint8_t> &p_data);
- static Error _save_pack_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
- static Error _save_pack_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
+ static Error _save_pack_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed);
+ static Error _save_pack_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed);
static Error _pack_add_shared_object(void *p_userdata, const SharedObject &p_so);
static Error _remove_pack_file(void *p_userdata, const String &p_path);
- static Error _save_zip_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
- static Error _save_zip_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
+ static Error _save_zip_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed);
+ static Error _save_zip_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed);
static Error _zip_add_shared_object(void *p_userdata, const SharedObject &p_so);
struct ScriptCallbackData {
@@ -129,12 +129,14 @@ private:
Callable so_cb;
};
- static Error _script_save_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
+ static Error _script_save_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed);
static Error _script_add_shared_object(void *p_userdata, const SharedObject &p_so);
void _edit_files_with_filter(Ref<DirAccess> &da, const Vector<String> &p_filters, HashSet<String> &r_list, bool exclude);
void _edit_filter_list(HashSet<String> &r_list, const String &p_filter, bool exclude);
+ static Vector<uint8_t> _filter_extension_list_config_file(const String &p_config_path, const HashSet<String> &p_paths);
+
struct FileExportCache {
uint64_t source_modified_time = 0;
String source_md5;
diff --git a/editor/export/editor_export_platform_pc.cpp b/editor/export/editor_export_platform_pc.cpp
index 4eff096840..15d684cac5 100644
--- a/editor/export/editor_export_platform_pc.cpp
+++ b/editor/export/editor_export_platform_pc.cpp
@@ -223,13 +223,13 @@ Error EditorExportPlatformPC::export_project_data(const Ref<EditorExportPreset>
if (err == OK) {
err = da->copy_dir(src_path, target_path, -1, true);
if (err != OK) {
- add_message(EXPORT_MESSAGE_ERROR, TTR("GDExtension"), TTR(vformat("Failed to copy shared object \"%s\".", src_path)));
+ add_message(EXPORT_MESSAGE_ERROR, TTR("GDExtension"), vformat(TTR("Failed to copy shared object \"%s\"."), src_path));
}
}
} else {
err = da->copy(src_path, target_path);
if (err != OK) {
- add_message(EXPORT_MESSAGE_ERROR, TTR("GDExtension"), TTR(vformat("Failed to copy shared object \"%s\".", src_path)));
+ add_message(EXPORT_MESSAGE_ERROR, TTR("GDExtension"), vformat(TTR("Failed to copy shared object \"%s\"."), src_path));
}
if (err == OK) {
err = sign_shared_object(p_preset, p_debug, target_path);
diff --git a/editor/export/editor_export_preset.cpp b/editor/export/editor_export_preset.cpp
index da7059b777..8ff5dd7551 100644
--- a/editor/export/editor_export_preset.cpp
+++ b/editor/export/editor_export_preset.cpp
@@ -451,6 +451,15 @@ String EditorExportPreset::get_enc_ex_filter() const {
return enc_ex_filters;
}
+void EditorExportPreset::set_seed(uint64_t p_seed) {
+ seed = p_seed;
+ EditorExport::singleton->save_presets();
+}
+
+uint64_t EditorExportPreset::get_seed() const {
+ return seed;
+}
+
void EditorExportPreset::set_enc_pck(bool p_enabled) {
enc_pck = p_enabled;
EditorExport::singleton->save_presets();
diff --git a/editor/export/editor_export_preset.h b/editor/export/editor_export_preset.h
index af3a23fc50..4834a483eb 100644
--- a/editor/export/editor_export_preset.h
+++ b/editor/export/editor_export_preset.h
@@ -92,6 +92,7 @@ private:
String enc_ex_filters;
bool enc_pck = false;
bool enc_directory = false;
+ uint64_t seed = 0;
String script_key;
int script_mode = MODE_SCRIPT_BINARY_TOKENS_COMPRESSED;
@@ -165,6 +166,9 @@ public:
void set_enc_ex_filter(const String &p_filter);
String get_enc_ex_filter() const;
+ void set_seed(uint64_t p_seed);
+ uint64_t get_seed() const;
+
void set_enc_pck(bool p_enabled);
bool get_enc_pck() const;
diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp
index a3cd6523e9..0fc62416af 100644
--- a/editor/export/project_export.cpp
+++ b/editor/export/project_export.cpp
@@ -382,10 +382,16 @@ void ProjectExportDialog::_edit_preset(int p_index) {
bool enc_pck_mode = current->get_enc_pck();
enc_pck->set_pressed(enc_pck_mode);
+ uint64_t seed = current->get_seed();
+ if (!updating_seed) {
+ seed_input->set_text(itos(seed));
+ }
+
enc_directory->set_disabled(!enc_pck_mode);
enc_in_filters->set_editable(enc_pck_mode);
enc_ex_filters->set_editable(enc_pck_mode);
script_key->set_editable(enc_pck_mode);
+ seed_input->set_editable(enc_pck_mode);
bool enc_directory_mode = current->get_enc_directory();
enc_directory->set_pressed(enc_directory_mode);
@@ -591,6 +597,21 @@ void ProjectExportDialog::_enc_pck_changed(bool p_pressed) {
_update_current_preset();
}
+void ProjectExportDialog::_seed_input_changed(const String &p_text) {
+ if (updating) {
+ return;
+ }
+
+ Ref<EditorExportPreset> current = get_current_preset();
+ ERR_FAIL_COND(current.is_null());
+
+ current->set_seed(seed_input->get_text().to_int());
+
+ updating_seed = true;
+ _update_current_preset();
+ updating_seed = false;
+}
+
void ProjectExportDialog::_enc_directory_changed(bool p_pressed) {
if (updating) {
return;
@@ -1185,6 +1206,9 @@ void ProjectExportDialog::_export_pck_zip_selected(const String &p_path) {
bool export_debug = fd_option.get(TTR("Export With Debug"), true);
bool export_as_patch = fd_option.get(TTR("Export As Patch"), true);
+ EditorSettings::get_singleton()->set_project_metadata("export_options", "export_debug", export_debug);
+ EditorSettings::get_singleton()->set_project_metadata("export_options", "export_as_patch", export_as_patch);
+
if (p_path.ends_with(".zip")) {
if (export_as_patch) {
platform->export_zip_patch(current, export_debug, p_path);
@@ -1284,6 +1308,8 @@ void ProjectExportDialog::_export_project_to_path(const String &p_path) {
Dictionary fd_option = export_project->get_selected_options();
bool export_debug = fd_option.get(TTR("Export With Debug"), true);
+ EditorSettings::get_singleton()->set_project_metadata("export_options", "export_debug", export_debug);
+
Error err = platform->export_project(current, export_debug, current->get_export_path(), 0);
result_dialog_log->clear();
if (err != ERR_SKIP) {
@@ -1623,6 +1649,10 @@ ProjectExportDialog::ProjectExportDialog() {
sec_vb->add_child(script_key_error);
sections->add_child(sec_scroll_container);
+ seed_input = memnew(LineEdit);
+ seed_input->connect(SceneStringName(text_changed), callable_mp(this, &ProjectExportDialog::_seed_input_changed));
+ sec_vb->add_margin_child(TTR("Initialization vector seed"), seed_input);
+
Label *sec_info = memnew(Label);
sec_info->set_text(TTR("Note: Encryption key needs to be stored in the binary,\nyou need to build the export templates from source."));
sec_vb->add_child(sec_info);
@@ -1749,9 +1779,9 @@ ProjectExportDialog::ProjectExportDialog() {
export_project->connect("file_selected", callable_mp(this, &ProjectExportDialog::_export_project_to_path));
export_project->get_line_edit()->connect(SceneStringName(text_changed), callable_mp(this, &ProjectExportDialog::_validate_export_path));
- export_project->add_option(TTR("Export With Debug"), Vector<String>(), true);
- export_pck_zip->add_option(TTR("Export With Debug"), Vector<String>(), true);
- export_pck_zip->add_option(TTR("Export As Patch"), Vector<String>(), true);
+ export_project->add_option(TTR("Export With Debug"), Vector<String>(), EditorSettings::get_singleton()->get_project_metadata("export_options", "export_debug", true));
+ export_pck_zip->add_option(TTR("Export With Debug"), Vector<String>(), EditorSettings::get_singleton()->get_project_metadata("export_options", "export_debug", true));
+ export_pck_zip->add_option(TTR("Export As Patch"), Vector<String>(), EditorSettings::get_singleton()->get_project_metadata("export_options", "export_as_patch", true));
set_hide_on_ok(false);
diff --git a/editor/export/project_export.h b/editor/export/project_export.h
index bbf0d81228..68676bfc84 100644
--- a/editor/export/project_export.h
+++ b/editor/export/project_export.h
@@ -172,6 +172,7 @@ class ProjectExportDialog : public ConfirmationDialog {
CheckButton *enc_directory = nullptr;
LineEdit *enc_in_filters = nullptr;
LineEdit *enc_ex_filters = nullptr;
+ LineEdit *seed_input = nullptr;
OptionButton *script_mode = nullptr;
@@ -192,9 +193,11 @@ class ProjectExportDialog : public ConfirmationDialog {
bool updating_script_key = false;
bool updating_enc_filters = false;
+ bool updating_seed = false;
void _enc_pck_changed(bool p_pressed);
void _enc_directory_changed(bool p_pressed);
void _enc_filters_changed(const String &p_text);
+ void _seed_input_changed(const String &p_text);
void _script_encryption_key_changed(const String &p_key);
bool _validate_script_encryption_key(const String &p_key);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index fcd5a572b4..c7e12d1f3b 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -137,7 +137,7 @@ bool FileSystemList::edit_selected() {
String name = get_item_text(s);
line_editor->set_text(name);
- line_editor->select(0, name.rfind("."));
+ line_editor->select(0, name.rfind_char('.'));
popup_edit_commited = false; // Start edit popup processing.
popup_editor->popup();
@@ -203,9 +203,7 @@ Ref<Texture2D> FileSystemDock::_get_tree_item_icon(bool p_is_valid, const String
}
}
-bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path) {
- bool parent_should_expand = false;
-
+void FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path) {
// Create a tree item for the subdirectory.
TreeItem *subdirectory_item = tree->create_item(p_parent);
String dname = p_dir->get_name();
@@ -213,6 +211,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
if (dname.is_empty()) {
dname = "res://";
+ resources_item = subdirectory_item;
}
// Set custom folder color (if applicable).
@@ -258,16 +257,13 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
} else {
subdirectory_item->set_collapsed(!uncollapsed_paths.has(lpath));
}
- if (!searched_tokens.is_empty() && _matches_all_search_tokens(dname)) {
- parent_should_expand = true;
- }
// Create items for all subdirectories.
bool reversed = file_sort == FileSortOption::FILE_SORT_NAME_REVERSE;
for (int i = reversed ? p_dir->get_subdir_count() - 1 : 0;
reversed ? i >= 0 : i < p_dir->get_subdir_count();
reversed ? i-- : i++) {
- parent_should_expand = (_create_tree(subdirectory_item, p_dir->get_subdir(i), uncollapsed_paths, p_select_in_favorites, p_unfold_path) || parent_should_expand);
+ _create_tree(subdirectory_item, p_dir->get_subdir(i), uncollapsed_paths, p_select_in_favorites, p_unfold_path);
}
// Create all items for the files in the subdirectory.
@@ -283,17 +279,6 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
continue;
}
- String file_name = p_dir->get_file(i);
- if (!searched_tokens.is_empty()) {
- if (!_matches_all_search_tokens(file_name)) {
- // The searched string is not in the file name, we skip it.
- continue;
- } else {
- // We expand all parents.
- parent_should_expand = true;
- }
- }
-
FileInfo file_info;
file_info.name = p_dir->get_file(i);
file_info.type = p_dir->get_file_type(i);
@@ -346,24 +331,12 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
subdirectory_item->set_as_cursor(0);
}
}
-
- if (!searched_tokens.is_empty()) {
- if (parent_should_expand) {
- subdirectory_item->set_collapsed(false);
- } else if (dname != "res://") {
- subdirectory_item->get_parent()->remove_child(subdirectory_item);
- memdelete(subdirectory_item);
- }
- }
-
- return parent_should_expand;
}
Vector<String> FileSystemDock::get_uncollapsed_paths() const {
Vector<String> uncollapsed_paths;
TreeItem *root = tree->get_root();
if (root) {
- TreeItem *favorites_item = root->get_first_child();
if (!favorites_item->is_collapsed()) {
uncollapsed_paths.push_back(favorites_item->get_metadata(0));
}
@@ -400,7 +373,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
TreeItem *root = tree->create_item();
// Handles the favorites.
- TreeItem *favorites_item = tree->create_item(root);
+ favorites_item = tree->create_item(root);
favorites_item->set_icon(0, get_editor_theme_icon(SNAME("Favorites")));
favorites_item->set_text(0, TTR("Favorites:"));
favorites_item->set_metadata(0, "Favorites");
@@ -453,24 +426,22 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
color = Color(1, 1, 1);
}
- if (searched_tokens.is_empty() || _matches_all_search_tokens(text)) {
- TreeItem *ti = tree->create_item(favorites_item);
- ti->set_text(0, text);
- ti->set_icon(0, icon);
- ti->set_icon_modulate(0, color);
- ti->set_tooltip_text(0, favorite);
- ti->set_selectable(0, true);
- ti->set_metadata(0, favorite);
- if (p_select_in_favorites && favorite == current_path) {
- ti->select(0);
- ti->set_as_cursor(0);
- }
- if (!favorite.ends_with("/")) {
- Array udata;
- udata.push_back(tree_update_id);
- udata.push_back(ti);
- EditorResourcePreview::get_singleton()->queue_resource_preview(favorite, this, "_tree_thumbnail_done", udata);
- }
+ TreeItem *ti = tree->create_item(favorites_item);
+ ti->set_text(0, text);
+ ti->set_icon(0, icon);
+ ti->set_icon_modulate(0, color);
+ ti->set_tooltip_text(0, favorite);
+ ti->set_selectable(0, true);
+ ti->set_metadata(0, favorite);
+ if (p_select_in_favorites && favorite == current_path) {
+ ti->select(0);
+ ti->set_as_cursor(0);
+ }
+ if (!favorite.ends_with("/")) {
+ Array udata;
+ udata.push_back(tree_update_id);
+ udata.push_back(ti);
+ EditorResourcePreview::get_singleton()->queue_resource_preview(favorite, this, "_tree_thumbnail_done", udata);
}
}
@@ -676,7 +647,6 @@ void FileSystemDock::_tree_multi_selected(Object *p_item, int p_column, bool p_s
return;
}
- TreeItem *favorites_item = tree->get_root()->get_first_child();
if (selected->get_parent() == favorites_item && !String(selected->get_metadata(0)).ends_with("/")) {
// Go to the favorites if we click in the favorites and the path has changed.
current_path = "Favorites";
@@ -771,6 +741,36 @@ void FileSystemDock::_navigate_to_path(const String &p_path, bool p_select_in_fa
}
}
+bool FileSystemDock::_update_filtered_items(TreeItem *p_tree_item) {
+ TreeItem *item = p_tree_item;
+ if (!item) {
+ item = tree->get_root();
+ }
+ ERR_FAIL_NULL_V(item, false);
+
+ bool keep_visible = false;
+ for (TreeItem *child = item->get_first_child(); child; child = child->get_next()) {
+ keep_visible = _update_filtered_items(child) || keep_visible;
+ }
+
+ if (searched_tokens.is_empty()) {
+ item->set_visible(true);
+ // Always uncollapse root (the hidden item above res:// and favorites).
+ item->set_collapsed(item != tree->get_root() && !uncollapsed_paths_before_search.has(item->get_metadata(0)));
+ return true;
+ }
+
+ if (keep_visible) {
+ item->set_collapsed(false);
+ } else {
+ // res:// and favorites are always visible.
+ keep_visible = item == resources_item || item == favorites_item;
+ keep_visible = keep_visible || _matches_all_search_tokens(item->get_text(0));
+ }
+ item->set_visible(keep_visible);
+ return keep_visible;
+}
+
void FileSystemDock::navigate_to_path(const String &p_path) {
file_list_search_box->clear();
_navigate_to_path(p_path);
@@ -2028,7 +2028,6 @@ Vector<String> FileSystemDock::_tree_get_selected(bool remove_self_inclusion, bo
// Build a list of selected items with the active one at the first position.
Vector<String> selected_strings;
- TreeItem *favorites_item = tree->get_root()->get_first_child();
TreeItem *cursor_item = tree->get_selected();
if (cursor_item && (p_include_unselected_cursor || cursor_item->is_selected(0)) && cursor_item != favorites_item) {
selected_strings.push_back(cursor_item->get_metadata(0));
@@ -2433,7 +2432,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
if (to_rename.is_file) {
String name = to_rename.path.get_file();
- tree->set_editor_selection(0, name.rfind("."));
+ tree->set_editor_selection(0, name.rfind_char('.'));
} else {
String name = to_rename.path.left(-1).get_file(); // Removes the "/" suffix for folders.
tree->set_editor_selection(0, name.length());
@@ -2637,16 +2636,12 @@ void FileSystemDock::_search_changed(const String &p_text, const Control *p_from
tree_search_box->set_text(searched_string);
}
- bool unfold_path = (p_text.is_empty() && !current_path.is_empty());
- switch (display_mode) {
- case DISPLAY_MODE_TREE_ONLY: {
- _update_tree(searched_tokens.is_empty() ? uncollapsed_paths_before_search : Vector<String>(), false, false, unfold_path);
- } break;
- case DISPLAY_MODE_HSPLIT:
- case DISPLAY_MODE_VSPLIT: {
- _update_file_list(false);
- _update_tree(searched_tokens.is_empty() ? uncollapsed_paths_before_search : Vector<String>(), false, false, unfold_path);
- } break;
+ _update_filtered_items();
+ if (display_mode == DISPLAY_MODE_HSPLIT || display_mode == DISPLAY_MODE_VSPLIT) {
+ _update_file_list(false);
+ }
+ if (searched_tokens.is_empty()) {
+ _navigate_to_path(current_path);
}
}
@@ -2786,7 +2781,6 @@ Variant FileSystemDock::get_drag_data_fw(const Point2 &p_point, Control *p_from)
// Check if the first selected is in favorite.
TreeItem *selected = tree->get_next_selected(tree->get_root());
while (selected) {
- TreeItem *favorites_item = tree->get_root()->get_first_child();
if (selected == favorites_item) {
// The "Favorites" item is not draggable.
return Variant();
@@ -2838,10 +2832,6 @@ bool FileSystemDock::can_drop_data_fw(const Point2 &p_point, const Variant &p_da
}
int drop_section = tree->get_drop_section_at_position(p_point);
- TreeItem *favorites_item = tree->get_root()->get_first_child();
-
- TreeItem *resources_item = favorites_item->get_next();
-
if (ti == favorites_item) {
return (drop_section == 1); // The parent, first fav.
}
@@ -2922,9 +2912,6 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
int drop_position;
Vector<String> drag_files = drag_data["files"];
- TreeItem *favorites_item = tree->get_root()->get_first_child();
- TreeItem *resources_item = favorites_item->get_next();
-
if (ti == favorites_item) {
// Drop on the favorite folder.
drop_position = 0;
@@ -3352,7 +3339,6 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, const Vect
[[maybe_unused]] bool added_separator = false;
if (favorites_list.has(fpath)) {
- TreeItem *favorites_item = tree->get_root()->get_first_child();
TreeItem *cursor_item = tree->get_selected();
bool is_item_in_favorites = false;
while (cursor_item != nullptr) {
@@ -3672,10 +3658,10 @@ void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) {
tree_item->select(0);
} else {
// Find parent folder.
- fpath = fpath.substr(0, fpath.rfind("/") + 1);
+ fpath = fpath.substr(0, fpath.rfind_char('/') + 1);
if (fpath.size() > String("res://").size()) {
fpath = fpath.left(fpath.size() - 2); // Remove last '/'.
- const int slash_idx = fpath.rfind("/");
+ const int slash_idx = fpath.rfind_char('/');
fpath = fpath.substr(slash_idx + 1, fpath.size() - slash_idx - 1);
}
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index fe83129c07..d2e403a8af 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -232,6 +232,8 @@ private:
FileSystemTree *tree = nullptr;
FileSystemList *files = nullptr;
bool import_dock_needs_update = false;
+ TreeItem *resources_item = nullptr;
+ TreeItem *favorites_item = nullptr;
bool holding_branch = false;
Vector<TreeItem *> tree_items_selected_on_drag_begin;
@@ -245,9 +247,10 @@ private:
void _reselect_items_selected_on_drag_begin(bool reset = false);
Ref<Texture2D> _get_tree_item_icon(bool p_is_valid, const String &p_file_type, const String &p_icon_path);
- bool _create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path = false);
+ void _create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, Vector<String> &uncollapsed_paths, bool p_select_in_favorites, bool p_unfold_path = false);
void _update_tree(const Vector<String> &p_uncollapsed_paths = Vector<String>(), bool p_uncollapse_root = false, bool p_select_in_favorites = false, bool p_unfold_path = false);
void _navigate_to_path(const String &p_path, bool p_select_in_favorites = false);
+ bool _update_filtered_items(TreeItem *p_tree_item = nullptr);
void _file_list_gui_input(Ref<InputEvent> p_event);
void _tree_gui_input(Ref<InputEvent> p_event);
diff --git a/editor/gui/editor_file_dialog.cpp b/editor/gui/editor_file_dialog.cpp
index ceff62723f..0381609804 100644
--- a/editor/gui/editor_file_dialog.cpp
+++ b/editor/gui/editor_file_dialog.cpp
@@ -65,7 +65,7 @@ void EditorFileDialog::_native_popup() {
} else if (access == ACCESS_USERDATA) {
root = OS::get_singleton()->get_user_data_dir();
}
- DisplayServer::get_singleton()->file_dialog_with_options_show(get_title(), ProjectSettings::get_singleton()->globalize_path(dir->get_text()), root, file->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), filters, _get_options(), callable_mp(this, &EditorFileDialog::_native_dialog_cb));
+ DisplayServer::get_singleton()->file_dialog_with_options_show(get_translated_title(), ProjectSettings::get_singleton()->globalize_path(dir->get_text()), root, file->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), processed_filters, _get_options(), callable_mp(this, &EditorFileDialog::_native_dialog_cb));
}
void EditorFileDialog::popup(const Rect2i &p_rect) {
@@ -156,7 +156,7 @@ void EditorFileDialog::popup_file_dialog() {
}
void EditorFileDialog::_focus_file_text() {
- int lp = file->get_text().rfind(".");
+ int lp = file->get_text().rfind_char('.');
if (lp != -1) {
file->select(0, lp);
file->grab_focus();
@@ -1148,37 +1148,54 @@ void EditorFileDialog::_filter_selected(int) {
void EditorFileDialog::update_filters() {
filter->clear();
+ processed_filters.clear();
if (filters.size() > 1) {
String all_filters;
+ String all_filters_full;
const int max_filters = 5;
for (int i = 0; i < MIN(max_filters, filters.size()); i++) {
- String flt = filters[i].get_slice(";", 0).strip_edges();
+ String flt = filters[i].get_slicec(';', 0).strip_edges();
if (i > 0) {
all_filters += ", ";
}
all_filters += flt;
}
+ for (int i = 0; i < filters.size(); i++) {
+ String flt = filters[i].get_slicec(';', 0).strip_edges();
+ if (i > 0) {
+ all_filters_full += ",";
+ }
+ all_filters_full += flt;
+ }
if (max_filters < filters.size()) {
all_filters += ", ...";
}
- filter->add_item(TTR("All Recognized") + " (" + all_filters + ")");
+ String f = TTR("All Recognized") + " (" + all_filters + ")";
+ filter->add_item(f);
+ processed_filters.push_back(all_filters_full + ";" + f);
}
for (int i = 0; i < filters.size(); i++) {
- String flt = filters[i].get_slice(";", 0).strip_edges();
+ String flt = filters[i].get_slicec(';', 0).strip_edges();
String desc = filters[i].get_slice(";", 1).strip_edges();
if (desc.length()) {
- filter->add_item(desc + " (" + flt + ")");
+ String f = desc + " (" + flt + ")";
+ filter->add_item(f);
+ processed_filters.push_back(flt + ";" + f);
} else {
- filter->add_item("(" + flt + ")");
+ String f = "(" + flt + ")";
+ filter->add_item(f);
+ processed_filters.push_back(flt + ";" + f);
}
}
- filter->add_item(TTR("All Files (*)"));
+ String f = TTR("All Files (*)");
+ filter->add_item(f);
+ processed_filters.push_back("*.*;" + f);
}
void EditorFileDialog::clear_filters() {
@@ -1246,7 +1263,7 @@ void EditorFileDialog::set_current_path(const String &p_path) {
if (!p_path.size()) {
return;
}
- int pos = MAX(p_path.rfind("/"), p_path.rfind("\\"));
+ int pos = MAX(p_path.rfind_char('/'), p_path.rfind_char('\\'));
if (pos == -1) {
set_current_file(p_path);
} else {
diff --git a/editor/gui/editor_file_dialog.h b/editor/gui/editor_file_dialog.h
index 1922155133..7a928a6188 100644
--- a/editor/gui/editor_file_dialog.h
+++ b/editor/gui/editor_file_dialog.h
@@ -145,6 +145,7 @@ private:
void _push_history();
Vector<String> filters;
+ Vector<String> processed_filters;
bool previews_enabled = true;
bool preview_waiting = false;
diff --git a/editor/gui/editor_spin_slider.cpp b/editor/gui/editor_spin_slider.cpp
index 27b6bbafb7..aa9e9f841d 100644
--- a/editor/gui/editor_spin_slider.cpp
+++ b/editor/gui/editor_spin_slider.cpp
@@ -67,6 +67,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
} else {
set_value(get_value() - get_step());
}
+ emit_signal("updown_pressed");
return;
}
_grab_start();
@@ -437,7 +438,7 @@ void EditorSpinSlider::_draw_spin_slider() {
Vector2 scale = get_global_transform_with_canvas().get_scale();
grabber->set_scale(scale);
grabber->reset_size();
- grabber->set_position(get_global_position() + (grabber_rect.get_center() - grabber->get_size() * 0.5) * scale);
+ grabber->set_position((grabber_rect.get_center() - grabber->get_size() * 0.5) * scale);
if (mousewheel_over_grabber) {
Input::get_singleton()->warp_mouse(grabber->get_position() + grabber_rect.size);
@@ -696,6 +697,7 @@ void EditorSpinSlider::_bind_methods() {
ADD_SIGNAL(MethodInfo("grabbed"));
ADD_SIGNAL(MethodInfo("ungrabbed"));
+ ADD_SIGNAL(MethodInfo("updown_pressed"));
ADD_SIGNAL(MethodInfo("value_focus_entered"));
ADD_SIGNAL(MethodInfo("value_focus_exited"));
@@ -731,7 +733,7 @@ EditorSpinSlider::EditorSpinSlider() {
grabber = memnew(TextureRect);
add_child(grabber);
grabber->hide();
- grabber->set_as_top_level(true);
+ grabber->set_z_index(1);
grabber->set_mouse_filter(MOUSE_FILTER_STOP);
grabber->connect(SceneStringName(mouse_entered), callable_mp(this, &EditorSpinSlider::_grabber_mouse_entered));
grabber->connect(SceneStringName(mouse_exited), callable_mp(this, &EditorSpinSlider::_grabber_mouse_exited));
diff --git a/editor/gui/editor_toaster.cpp b/editor/gui/editor_toaster.cpp
index ffea1736a3..ff425ba65e 100644
--- a/editor/gui/editor_toaster.cpp
+++ b/editor/gui/editor_toaster.cpp
@@ -506,6 +506,14 @@ void EditorToaster::instant_close(Control *p_control) {
p_control->set_modulate(Color(1, 1, 1, 0));
}
+void EditorToaster::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("push_toast", "message", "severity", "tooltip"), &EditorToaster::_popup_str, DEFVAL(EditorToaster::SEVERITY_INFO), DEFVAL(String()));
+
+ BIND_ENUM_CONSTANT(SEVERITY_INFO);
+ BIND_ENUM_CONSTANT(SEVERITY_WARNING);
+ BIND_ENUM_CONSTANT(SEVERITY_ERROR);
+}
+
EditorToaster *EditorToaster::get_singleton() {
return singleton;
}
diff --git a/editor/gui/editor_toaster.h b/editor/gui/editor_toaster.h
index 6fcc2ce3e9..0d0080945e 100644
--- a/editor/gui/editor_toaster.h
+++ b/editor/gui/editor_toaster.h
@@ -105,6 +105,7 @@ private:
void _toast_theme_changed(Control *p_control);
protected:
+ static void _bind_methods();
static EditorToaster *singleton;
void _notification(int p_what);
diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp
index c11da5dfdb..e89912d5bc 100644
--- a/editor/gui/scene_tree_editor.cpp
+++ b/editor/gui/scene_tree_editor.cpp
@@ -1098,8 +1098,19 @@ void SceneTreeEditor::rename_node(Node *p_node, const String &p_name, TreeItem *
// Trim leading/trailing whitespace to prevent node names from containing accidental whitespace, which would make it more difficult to get the node via `get_node()`.
new_name = new_name.strip_edges();
+ if (new_name.is_empty() && p_node->get_owner() != nullptr && !p_node->get_scene_file_path().is_empty()) {
+ // If name is empty and node is root of an instance, revert to the original name.
+ const Ref<PackedScene> node_scene = ResourceLoader::load(p_node->get_scene_file_path());
+ if (node_scene.is_valid()) {
+ const Ref<SceneState> &state = node_scene->get_state();
+ if (state->get_node_count() > 0) {
+ new_name = state->get_node_name(0); // Root's name.
+ }
+ }
+ }
+
if (new_name.is_empty()) {
- // If name is empty, fallback to class name.
+ // If name is still empty, fallback to class name.
if (GLOBAL_GET("editor/naming/node_name_casing").operator int() != NAME_CASING_PASCAL_CASE) {
new_name = Node::adjust_name_casing(p_node->get_class());
} else {
diff --git a/editor/icons/FlipWinding.svg b/editor/icons/FlipWinding.svg
new file mode 100644
index 0000000000..8964ca8d5d
--- /dev/null
+++ b/editor/icons/FlipWinding.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><rect width="4.596" height="4.596" x="5.7" y="5.7" fill="#e0e0e0" fill-opacity=".6" rx="1" ry="1" transform="rotate(45 8 8)"/><path fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 2a6 6 0 00-2.5 11m.5-3L6 14H2M9 14a6 6 0 002.5-11M11 6 10 2h4"/></svg> \ No newline at end of file
diff --git a/editor/icons/LookAtModifier3D.svg b/editor/icons/LookAtModifier3D.svg
new file mode 100644
index 0000000000..9315b297ef
--- /dev/null
+++ b/editor/icons/LookAtModifier3D.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g fill="#fc7f7f"><path d="m5.742 11.508c.916-2.959 3.507-4.508 5.592-4.508.803 0 1.673.223 2.492.658.297-.182.563-.423.768-.731.754-1.134.446-2.665-.688-3.419-.309-.205-.66-.338-1.026-.389-.188-1.349-1.433-2.291-2.782-2.103s-2.29 1.433-2.103 2.782c.051.367.184.717.389 1.026l-3.56 3.56c-1.134-.754-2.665-.446-3.419.688s-.446 2.664.688 3.419c.308.205.659.338 1.026.389.188 1.349 1.433 2.29 2.782 2.103.342-.048.658-.164.936-.333-.467-.612-.856-1.337-1.102-2.206-.085-.3-.085-.617.007-.936z"/><path d="m11.334 8c-1.704 0-3.861 1.299-4.637 3.804-.034.119-.034.246 0 .366.745 2.638 2.97 3.83 4.637 3.83s3.891-1.192 4.641-3.816c.034-.12.034-.247 0-.367-.734-2.526-2.938-3.817-4.641-3.817zm0 6.667c-1.473 0-2.667-1.194-2.667-2.667s1.194-2.666 2.667-2.666 2.667 1.193 2.667 2.666-1.194 2.667-2.667 2.667z"/><circle cx="11.334" cy="12" r="1.333"/></g></svg> \ No newline at end of file
diff --git a/editor/icons/RetargetModifier3D.svg b/editor/icons/RetargetModifier3D.svg
new file mode 100644
index 0000000000..2ca7af6c6e
--- /dev/null
+++ b/editor/icons/RetargetModifier3D.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g fill="#fc7f7f"><path d="m11.667 4.166h-3.334c-1.841 0-3.333 1.492-3.333 3.334.003 1.188.638 2.283 1.667 2.877v2.956c0 .597.317 1.146.833 1.444.254.146.54.221.833.221v.002h3.334v-.002c.293 0 .579-.075.833-.221.516-.299.833-.851.833-1.444v-2.956c1.028-.594 1.664-1.689 1.667-2.877 0-1.842-1.492-3.334-3.333-3.334zm-2.5 4.166h1.666v.834h-1.666zm-2.5-.832c0-.461.372-.834.833-.834s.833.373.833.834-.372.832-.833.832-.833-.371-.833-.832zm5.833 3.223v2.61h-.833v-.833h-.834v.833h-1.666v-.833h-.834v.833h-.833v-2.608-.725h.833v.832h.834v-.832h1.666v.832h.834v-.832h.833zm0-2.391c-.461 0-.833-.371-.833-.832s.372-.834.833-.834.833.373.833.834-.372.832-.833.832z"/><path d="m4.418 9.334h-.085v.833h-.833v-2.608-.725h.567c.323-2.072 2.104-3.668 4.266-3.668h2.445c-.473-1.263-1.682-2.166-3.111-2.166h-3.334c-1.841 0-3.333 1.492-3.333 3.334.003 1.188.638 2.283 1.667 2.877v2.956c0 .597.317 1.146.833 1.444.254.146.54.221.833.221v.002h1.334v-.929c-.538-.421-.962-.962-1.249-1.571zm-1.751-5c0-.461.372-.834.833-.834s.833.373.833.834-.372.832-.833.832-.833-.371-.833-.832z"/></g></svg> \ No newline at end of file
diff --git a/editor/import/3d/post_import_plugin_skeleton_renamer.cpp b/editor/import/3d/post_import_plugin_skeleton_renamer.cpp
index 3f6bfdcf05..700b2bc719 100644
--- a/editor/import/3d/post_import_plugin_skeleton_renamer.cpp
+++ b/editor/import/3d/post_import_plugin_skeleton_renamer.cpp
@@ -39,7 +39,7 @@
void PostImportPluginSkeletonRenamer::get_internal_import_options(InternalImportCategory p_category, List<ResourceImporter::ImportOption> *r_options) {
if (p_category == INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE) {
- r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/bone_renamer/rename_bones"), true));
+ r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/bone_renamer/rename_bones", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/bone_renamer/unique_node/make_unique"), true));
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::STRING, "retarget/bone_renamer/unique_node/skeleton_name"), "GeneralSkeleton"));
}
diff --git a/editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp b/editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp
index 64bec0532b..82940f9cef 100644
--- a/editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp
+++ b/editor/import/3d/post_import_plugin_skeleton_rest_fixer.cpp
@@ -33,6 +33,7 @@
#include "editor/import/3d/scene_import_settings.h"
#include "scene/3d/bone_attachment_3d.h"
#include "scene/3d/importer_mesh_instance_3d.h"
+#include "scene/3d/retarget_modifier_3d.h"
#include "scene/3d/skeleton_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/bone_map.h"
@@ -42,8 +43,18 @@ void PostImportPluginSkeletonRestFixer::get_internal_import_options(InternalImpo
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/apply_node_transforms"), true));
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/normalize_position_tracks"), true));
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/reset_all_bone_poses_after_import"), true));
- r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/overwrite_axis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
+
+ r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "retarget/rest_fixer/retarget_method", PROPERTY_HINT_ENUM, "None,Overwrite Axis,Use Retarget Modifier", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 1));
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/keep_global_rest_on_leftovers"), true));
+ String skeleton_bones_must_be_renamed_warning = String(
+ "The skeleton modifier option uses SkeletonProfile as a list of bone names and retargets by name matching. Without renaming, retargeting by modifier will not work and the track path of the animation will be broken and it will be not playbacked correctly."); // TODO: translate.
+ r_options->push_back(ResourceImporter::ImportOption(
+ PropertyInfo(
+ Variant::STRING, U"retarget/rest_fixer/\u26A0_validation_warning/skeleton_bones_must_be_renamed",
+ PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY),
+ Variant(skeleton_bones_must_be_renamed_warning)));
+ r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/use_global_pose"), true));
+ r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::STRING, "retarget/rest_fixer/original_skeleton_name"), "OriginalSkeleton"));
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/fix_silhouette/enable", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
// TODO: PostImportPlugin need to be implemented such as validate_option(PropertyInfo &property, const Dictionary &p_options).
// get_internal_option_visibility() is not sufficient because it can only retrieve options implemented in the core and can only read option values.
@@ -63,7 +74,11 @@ Variant PostImportPluginSkeletonRestFixer::get_internal_option_visibility(Intern
}
}
} else if (p_option == "retarget/rest_fixer/keep_global_rest_on_leftovers") {
- return bool(p_options["retarget/rest_fixer/overwrite_axis"]);
+ return int(p_options["retarget/rest_fixer/retarget_method"]) == 1;
+ } else if (p_option == "retarget/rest_fixer/original_skeleton_name" || p_option == "retarget/rest_fixer/use_global_pose") {
+ return int(p_options["retarget/rest_fixer/retarget_method"]) == 2;
+ } else if (p_option.begins_with("retarget/") && p_option.ends_with("skeleton_bones_must_be_renamed")) {
+ return int(p_options["retarget/rest_fixer/retarget_method"]) == 2 && bool(p_options["retarget/bone_renamer/rename_bones"]) == false;
}
}
return true;
@@ -147,7 +162,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
src_skeleton->set_bone_pose_position(src_idx, src_skeleton->get_bone_pose_position(src_idx) * scl);
}
- // Fix animation.
+ // Fix animation by changing node transform.
bones_to_process = src_skeleton->get_parentless_bones();
{
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
@@ -224,6 +239,10 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
List<StringName> anims;
ap->get_animation_list(&anims);
for (const StringName &name : anims) {
+ if (String(name).contains("/")) {
+ continue; // Avoid animation library which may be created by importer dynamically.
+ }
+
Ref<Animation> anim = ap->get_animation(name);
int track_len = anim->get_track_count();
@@ -454,8 +473,13 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
}
}
- // Overwrite axis.
- if (bool(p_options["retarget/rest_fixer/overwrite_axis"])) {
+ bool is_using_modifier = int(p_options["retarget/rest_fixer/retarget_method"]) == 2;
+ bool is_using_global_pose = bool(p_options["retarget/rest_fixer/use_global_pose"]);
+ Skeleton3D *orig_skeleton = nullptr;
+ Skeleton3D *profile_skeleton = nullptr;
+
+ // Retarget in some way.
+ if (int(p_options["retarget/rest_fixer/retarget_method"]) > 0) {
LocalVector<Transform3D> old_skeleton_rest;
LocalVector<Transform3D> old_skeleton_global_rest;
for (int i = 0; i < src_skeleton->get_bone_count(); i++) {
@@ -463,11 +487,151 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
old_skeleton_global_rest.push_back(src_skeleton->get_bone_global_rest(i));
}
+ // Build structure for modifier.
+ if (is_using_modifier) {
+ orig_skeleton = src_skeleton;
+
+ // Duplicate src_skeleton to modify animation tracks, it will memdelele after that animation track modification.
+ src_skeleton = memnew(Skeleton3D);
+ for (int i = 0; i < orig_skeleton->get_bone_count(); i++) {
+ src_skeleton->add_bone(orig_skeleton->get_bone_name(i));
+ src_skeleton->set_bone_rest(i, orig_skeleton->get_bone_rest(i));
+ src_skeleton->set_bone_pose(i, orig_skeleton->get_bone_pose(i));
+ }
+ for (int i = 0; i < orig_skeleton->get_bone_count(); i++) {
+ src_skeleton->set_bone_parent(i, orig_skeleton->get_bone_parent(i));
+ }
+ src_skeleton->set_motion_scale(orig_skeleton->get_motion_scale());
+
+ // Rename orig_skeleton (previous src_skeleton), since it is not animated by animation track with GeneralSkeleton.
+ String original_skeleton_name = String(p_options["retarget/rest_fixer/original_skeleton_name"]);
+ String skel_name = orig_skeleton->get_name();
+ ERR_FAIL_COND_MSG(original_skeleton_name.is_empty(), "Original skeleton name cannot be empty.");
+ ERR_FAIL_COND_MSG(original_skeleton_name == skel_name, "Original skeleton name must be different from unique skeleton name.");
+
+ // Rename profile skeleton to be general skeleton.
+ profile_skeleton = memnew(Skeleton3D);
+ bool is_unique = orig_skeleton->is_unique_name_in_owner();
+ if (is_unique) {
+ orig_skeleton->set_unique_name_in_owner(false);
+ }
+ orig_skeleton->set_name(original_skeleton_name);
+ profile_skeleton->set_name(skel_name);
+ if (is_unique) {
+ profile_skeleton->set_unique_name_in_owner(true);
+ }
+ // Build profile skeleton bones.
+ int len = profile->get_bone_size();
+ for (int i = 0; i < len; i++) {
+ profile_skeleton->add_bone(profile->get_bone_name(i));
+ profile_skeleton->set_bone_rest(i, profile->get_reference_pose(i));
+ }
+ for (int i = 0; i < len; i++) {
+ int target_parent = profile_skeleton->find_bone(profile->get_bone_parent(i));
+ if (target_parent >= 0) {
+ profile_skeleton->set_bone_parent(i, target_parent);
+ }
+ }
+ for (int i = 0; i < len; i++) {
+ Vector3 origin;
+ int found = orig_skeleton->find_bone(profile->get_bone_name(i));
+ String parent_name = profile->get_bone_parent(i);
+ if (found >= 0) {
+ origin = orig_skeleton->get_bone_global_rest(found).origin;
+ if (profile->get_bone_name(i) != profile->get_root_bone()) {
+ int src_parent = -1;
+ while (src_parent < 0 && !parent_name.is_empty()) {
+ src_parent = orig_skeleton->find_bone(parent_name);
+ parent_name = profile->get_bone_parent(profile->find_bone(parent_name));
+ }
+ if (src_parent >= 0) {
+ Transform3D parent_grest = orig_skeleton->get_bone_global_rest(src_parent);
+ origin = origin - parent_grest.origin;
+ }
+ }
+ }
+ int target_parent = profile_skeleton->find_bone(profile->get_bone_parent(i));
+ if (target_parent >= 0) {
+ origin = profile_skeleton->get_bone_global_rest(target_parent).basis.get_rotation_quaternion().xform_inv(origin);
+ }
+ profile_skeleton->set_bone_rest(i, Transform3D(profile_skeleton->get_bone_rest(i).basis, origin));
+ }
+ profile_skeleton->set_motion_scale(orig_skeleton->get_motion_scale());
+ profile_skeleton->reset_bone_poses();
+ // Make structure with modifier.
+ Node *owner = p_node->get_owner();
+
+ Node *pr = orig_skeleton->get_parent();
+ pr->add_child(profile_skeleton);
+ profile_skeleton->set_owner(owner);
+
+ RetargetModifier3D *mod = memnew(RetargetModifier3D);
+ profile_skeleton->add_child(mod);
+ mod->set_owner(owner);
+ mod->set_name("RetargetModifier3D");
+
+ orig_skeleton->set_owner(nullptr);
+ orig_skeleton->reparent(mod, false);
+ orig_skeleton->set_owner(owner);
+ orig_skeleton->set_unique_name_in_owner(true);
+
+ mod->set_use_global_pose(is_using_global_pose);
+ mod->set_profile(profile);
+
+ // Fix skeleton name in animation.
+ // Mapped skeleton is animated by %GenerarSkeleton:RenamedBoneName.
+ // Unmapped skeleton is animated by %OriginalSkeleton:OriginalBoneName.
+ if (is_using_modifier) {
+ TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
+ String general_skeleton_pathname = UNIQUE_NODE_PREFIX + profile_skeleton->get_name();
+ while (nodes.size()) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
+ List<StringName> anims;
+ ap->get_animation_list(&anims);
+ for (const StringName &name : anims) {
+ Ref<Animation> anim = ap->get_animation(name);
+ int track_len = anim->get_track_count();
+ for (int i = 0; i < track_len; i++) {
+ if (anim->track_get_path(i).get_name_count() == 0) {
+ return;
+ }
+ if (anim->track_get_path(i).get_name(0) == general_skeleton_pathname) {
+ bool replace = false;
+ if (anim->track_get_path(i).get_subname_count() > 0) {
+ int found = profile_skeleton->find_bone(anim->track_get_path(i).get_concatenated_subnames());
+ if (found < 0) {
+ replace = true;
+ }
+ } else {
+ replace = true;
+ }
+ if (replace) {
+ String path_string = UNIQUE_NODE_PREFIX + original_skeleton_name;
+ if (anim->track_get_path(i).get_name_count() > 1) {
+ Vector<StringName> names = anim->track_get_path(i).get_names();
+ names.remove_at(0);
+ for (int j = 0; j < names.size(); j++) {
+ path_string += "/" + names[i].operator String();
+ }
+ }
+ if (anim->track_get_path(i).get_subname_count() > 0) {
+ path_string = path_string + String(":") + anim->track_get_path(i).get_concatenated_subnames();
+ }
+ anim->track_set_path(i, path_string);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
bool keep_global_rest_leftovers = bool(p_options["retarget/rest_fixer/keep_global_rest_on_leftovers"]);
// Scan hierarchy and populate a whitelist of unmapped bones without mapped descendants.
+ // When both is_using_modifier and is_using_global_pose are enabled, this array is used for detecting warning.
Vector<int> keep_bone_rest;
- if (keep_global_rest_leftovers) {
+ if (is_using_modifier || keep_global_rest_leftovers) {
Vector<int> bones_to_process = src_skeleton->get_parentless_bones();
while (bones_to_process.size() > 0) {
int src_idx = bones_to_process[0];
@@ -526,12 +690,14 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
if (src_parent_idx >= 0) {
src_pg = src_skeleton->get_bone_global_rest(src_parent_idx).basis;
}
-
int prof_idx = profile->find_bone(src_bone_name);
if (prof_idx >= 0) {
- tgt_rot = src_pg.inverse() * prof_skeleton->get_bone_global_rest(prof_idx).basis; // Mapped bone uses reference pose.
+ // Mapped bone uses reference pose.
+ // It is fine to change rest here even though is_using_modifier is enabled, since next process is aborted with unmapped bones.
+ tgt_rot = src_pg.inverse() * prof_skeleton->get_bone_global_rest(prof_idx).basis;
} else if (keep_global_rest_leftovers && keep_bone_rest.has(src_idx)) {
- tgt_rot = src_pg.inverse() * old_skeleton_global_rest[src_idx].basis; // Non-Mapped bone without mapped children keeps global rest.
+ // Non-Mapped bones without mapped children keeps global rest.
+ tgt_rot = src_pg.inverse() * old_skeleton_global_rest[src_idx].basis;
}
}
@@ -548,7 +714,8 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
src_skeleton->set_bone_rest(src_idx, Transform3D(tgt_rot, diff.xform(src_skeleton->get_bone_rest(src_idx).origin)));
}
- // Fix animation.
+ // Fix animation by changing rest.
+ bool warning_detected = false;
{
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
while (nodes.size()) {
@@ -573,7 +740,9 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
ERR_CONTINUE(!node);
Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
- if (!track_skeleton || track_skeleton != src_skeleton) {
+ if (!track_skeleton ||
+ (is_using_modifier && track_skeleton != profile_skeleton && track_skeleton != orig_skeleton) ||
+ (!is_using_modifier && track_skeleton != src_skeleton)) {
continue;
}
@@ -584,6 +753,16 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
int bone_idx = src_skeleton->find_bone(bn);
+ if (is_using_modifier) {
+ int prof_idx = profile->find_bone(bn);
+ if (prof_idx < 0) {
+ if (keep_bone_rest.has(bone_idx)) {
+ warning_detected = true;
+ }
+ continue; // If is_using_modifier, the original skeleton rest is not changed.
+ }
+ }
+
Transform3D old_rest = old_skeleton_rest[bone_idx];
Transform3D new_rest = src_skeleton->get_bone_rest(bone_idx);
Transform3D old_pg;
@@ -629,6 +808,13 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
}
}
}
+ if (is_using_global_pose && warning_detected) {
+ // TODO:
+ // Theoretically, if A and its conversion are calculated correctly taking into account the difference in the number of bones,
+ // there is no need to disable use_global_pose, but this is probably a fairly niche case.
+ WARN_PRINT_ED("Animated extra bone between mapped bones detected, consider disabling Use Global Pose option to prevent that the pose origin be overridden by the RetargetModifier3D.");
+ }
+
if (p_options.has("retarget/rest_fixer/reset_all_bone_poses_after_import") && !bool(p_options["retarget/rest_fixer/reset_all_bone_poses_after_import"])) {
// If Reset All Bone Poses After Import is disabled, preserve the original bone pose, adjusted for the new bone rolls.
for (int bone_idx = 0; bone_idx < src_skeleton->get_bone_count(); bone_idx++) {
@@ -654,6 +840,11 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
}
}
+ if (is_using_modifier) {
+ memdelete(src_skeleton);
+ src_skeleton = profile_skeleton;
+ }
+
is_rest_changed = true;
}
@@ -681,7 +872,9 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
ERR_CONTINUE(!node);
Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
- if (!track_skeleton || track_skeleton != src_skeleton) {
+ if (!track_skeleton ||
+ (is_using_modifier && track_skeleton != profile_skeleton && track_skeleton != orig_skeleton) ||
+ (!is_using_modifier && track_skeleton != src_skeleton)) {
continue;
}
@@ -696,7 +889,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
}
}
- if (is_rest_changed) {
+ if (!is_using_modifier && is_rest_changed) {
// Fix skin.
{
HashSet<Ref<Skin>> mutated_skins;
@@ -766,6 +959,14 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
src_skeleton->set_bone_pose_rotation(i, fixed_rest.basis.get_rotation_quaternion());
src_skeleton->set_bone_pose_scale(i, fixed_rest.basis.get_scale());
}
+ if (orig_skeleton) {
+ for (int i = 0; i < orig_skeleton->get_bone_count(); i++) {
+ Transform3D fixed_rest = orig_skeleton->get_bone_rest(i);
+ orig_skeleton->set_bone_pose_position(i, fixed_rest.origin);
+ orig_skeleton->set_bone_pose_rotation(i, fixed_rest.basis.get_rotation_quaternion());
+ orig_skeleton->set_bone_pose_scale(i, fixed_rest.basis.get_scale());
+ }
+ }
}
}
diff --git a/editor/import/3d/post_import_plugin_skeleton_track_organizer.cpp b/editor/import/3d/post_import_plugin_skeleton_track_organizer.cpp
index 53bcc59fcb..98312d3521 100644
--- a/editor/import/3d/post_import_plugin_skeleton_track_organizer.cpp
+++ b/editor/import/3d/post_import_plugin_skeleton_track_organizer.cpp
@@ -39,7 +39,7 @@ void PostImportPluginSkeletonTrackOrganizer::get_internal_import_options(Interna
if (p_category == INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE) {
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/remove_tracks/except_bone_transform"), false));
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/remove_tracks/unimportant_positions"), true));
- r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/remove_tracks/unmapped_bones"), false));
+ r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "retarget/remove_tracks/unmapped_bones", PROPERTY_HINT_ENUM, "None,Remove,Separate Library"), 0));
}
}
@@ -61,9 +61,9 @@ void PostImportPluginSkeletonTrackOrganizer::internal_process(InternalImportCate
}
bool remove_except_bone = bool(p_options["retarget/remove_tracks/except_bone_transform"]);
bool remove_positions = bool(p_options["retarget/remove_tracks/unimportant_positions"]);
- bool remove_unmapped_bones = bool(p_options["retarget/remove_tracks/unmapped_bones"]);
+ int separate_unmapped_bones = int(p_options["retarget/remove_tracks/unmapped_bones"]);
- if (!remove_positions && !remove_unmapped_bones) {
+ if (!remove_positions && separate_unmapped_bones == 0) {
return;
}
@@ -72,10 +72,16 @@ void PostImportPluginSkeletonTrackOrganizer::internal_process(InternalImportCate
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
List<StringName> anims;
ap->get_animation_list(&anims);
+
+ Ref<AnimationLibrary> unmapped_al;
+ unmapped_al.instantiate();
+
for (const StringName &name : anims) {
Ref<Animation> anim = ap->get_animation(name);
int track_len = anim->get_track_count();
Vector<int> remove_indices;
+ Vector<int> mapped_bone_indices;
+ Vector<int> unmapped_bone_indices;
for (int i = 0; i < track_len; i++) {
String track_path = String(anim->track_get_path(i).get_concatenated_names());
Node *node = (ap->get_node(ap->get_root_node()))->get_node(NodePath(track_path));
@@ -96,16 +102,19 @@ void PostImportPluginSkeletonTrackOrganizer::internal_process(InternalImportCate
StringName bn = anim->track_get_path(i).get_subname(0);
if (bn) {
int prof_idx = profile->find_bone(bone_map->find_profile_bone_name(bn));
- if (remove_unmapped_bones && prof_idx < 0) {
- remove_indices.push_back(i);
+ if (prof_idx < 0) {
+ unmapped_bone_indices.push_back(i);
continue;
}
if (remove_positions && anim->track_get_type(i) == Animation::TYPE_POSITION_3D && prof_idx >= 0) {
StringName prof_bn = profile->get_bone_name(prof_idx);
if (prof_bn == profile->get_root_bone() || prof_bn == profile->get_scale_base_bone()) {
+ mapped_bone_indices.push_back(i);
continue;
}
remove_indices.push_back(i);
+ } else {
+ mapped_bone_indices.push_back(i);
}
}
}
@@ -114,11 +123,34 @@ void PostImportPluginSkeletonTrackOrganizer::internal_process(InternalImportCate
}
}
+ if (separate_unmapped_bones == 2 && !unmapped_bone_indices.is_empty()) {
+ Ref<Animation> unmapped_anim = anim->duplicate();
+ Vector<int> to_delete;
+ to_delete.append_array(mapped_bone_indices);
+ to_delete.append_array(remove_indices);
+ to_delete.sort();
+ to_delete.reverse();
+ for (int E : to_delete) {
+ unmapped_anim->remove_track(E);
+ }
+ unmapped_al->add_animation(name, unmapped_anim);
+ }
+
+ if (separate_unmapped_bones >= 1) {
+ remove_indices.append_array(unmapped_bone_indices);
+ remove_indices.sort();
+ }
remove_indices.reverse();
for (int i = 0; i < remove_indices.size(); i++) {
anim->remove_track(remove_indices[i]);
}
}
+
+ if (unmapped_al->get_animation_list_size() == 0) {
+ unmapped_al.unref();
+ } else if (separate_unmapped_bones == 2) {
+ ap->add_animation_library("unmapped_bones", unmapped_al);
+ }
}
}
}
diff --git a/editor/import/3d/resource_importer_scene.cpp b/editor/import/3d/resource_importer_scene.cpp
index 86af9caf26..75f7d35b1c 100644
--- a/editor/import/3d/resource_importer_scene.cpp
+++ b/editor/import/3d/resource_importer_scene.cpp
@@ -2312,6 +2312,7 @@ bool ResourceImporterScene::get_internal_option_visibility(InternalImportCategor
}
}
+ // TODO: If there are more than 2 or equal get_internal_option_visibility method, visibility state is broken.
for (int i = 0; i < post_importer_plugins.size(); i++) {
Variant ret = post_importer_plugins.write[i]->get_internal_option_visibility(EditorScenePostImportPlugin::InternalImportCategory(p_category), _scene_import_type, p_option, p_options);
if (ret.get_type() == Variant::BOOL) {
diff --git a/editor/import/resource_importer_imagefont.cpp b/editor/import/resource_importer_imagefont.cpp
index 44ae2b5ff1..950058e88e 100644
--- a/editor/import/resource_importer_imagefont.cpp
+++ b/editor/import/resource_importer_imagefont.cpp
@@ -199,7 +199,7 @@ Error ResourceImporterImageFont::import(ResourceUID::ID p_source_id, const Strin
case STEP_OFF_Y_BEGIN: {
// Read advance and offset.
if (range[c] == ' ') {
- int next = range.find(" ", c + 1);
+ int next = range.find_char(' ', c + 1);
if (next < c) {
next = range.length();
}
diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp
index 71ccef4752..d72c15bc2a 100644
--- a/editor/import/resource_importer_texture.cpp
+++ b/editor/import/resource_importer_texture.cpp
@@ -241,7 +241,10 @@ void ResourceImporterTexture::get_import_options(const String &p_path, List<Impo
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/normal_map_invert_y"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/hdr_as_srgb"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/hdr_clamp_exposure"), false));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "process/size_limit", PROPERTY_HINT_RANGE, "0,4096,1"), 0));
+
+ // Maximum bound is the highest allowed value for lossy compression (the lowest common denominator).
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "process/size_limit", PROPERTY_HINT_RANGE, "0,16383,1"), 0));
+
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "detect_3d/compress_to", PROPERTY_HINT_ENUM, "Disabled,VRAM Compressed,Basis Universal"), (p_preset == PRESET_DETECT) ? 1 : 0));
// Do path based customization only if a path was passed.
@@ -454,7 +457,28 @@ Error ResourceImporterTexture::import(ResourceUID::ID p_source_id, const String
const bool normal_map_invert_y = p_options["process/normal_map_invert_y"];
// Support for texture streaming is not implemented yet.
const bool stream = false;
- const int size_limit = p_options["process/size_limit"];
+
+ int size_limit = p_options["process/size_limit"];
+ bool using_fallback_size_limit = false;
+ if (size_limit == 0) {
+ using_fallback_size_limit = true;
+ // If no size limit is defined, use a fallback size limit to prevent textures from looking incorrect or failing to import.
+ switch (compress_mode) {
+ case COMPRESS_LOSSY:
+ // Maximum WebP size on either axis.
+ size_limit = 16383;
+ break;
+ case COMPRESS_BASIS_UNIVERSAL:
+ // Maximum Basis Universal size on either axis.
+ size_limit = 16384;
+ break;
+ default:
+ // As of June 2024, no GPU can correctly display a texture larger than 32768 pixels on either axis.
+ size_limit = 32768;
+ break;
+ }
+ }
+
const bool hdr_as_srgb = p_options["process/hdr_as_srgb"];
if (hdr_as_srgb) {
loader_flags |= ImageFormatLoader::FLAG_FORCE_LINEAR;
@@ -523,11 +547,19 @@ Error ResourceImporterTexture::import(ResourceUID::ID p_source_id, const String
int new_width = size_limit;
int new_height = target_image->get_height() * new_width / target_image->get_width();
+ if (using_fallback_size_limit) {
+ // Only warn if downsizing occurred when the user did not explicitly request it.
+ WARN_PRINT(vformat("%s: Texture was downsized on import as its width (%d pixels) exceeded the importable size limit (%d pixels).", p_source_file, target_image->get_width(), size_limit));
+ }
target_image->resize(new_width, new_height, Image::INTERPOLATE_CUBIC);
} else {
int new_height = size_limit;
int new_width = target_image->get_width() * new_height / target_image->get_height();
+ if (using_fallback_size_limit) {
+ // Only warn if downsizing occurred when the user did not explicitly request it.
+ WARN_PRINT(vformat("%s: Texture was downsized on import as its height (%d pixels) exceeded the importable size limit (%d pixels).", p_source_file, target_image->get_height(), size_limit));
+ }
target_image->resize(new_width, new_height, Image::INTERPOLATE_CUBIC);
}
@@ -558,7 +590,7 @@ Error ResourceImporterTexture::import(ResourceUID::ID p_source_id, const String
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
const Color color = target_image->get_pixel(i, j);
- target_image->set_pixel(i, j, Color(color.r, 1 - color.g, color.b));
+ target_image->set_pixel(i, j, Color(color.r, 1 - color.g, color.b, color.a));
}
}
}
diff --git a/editor/input_event_configuration_dialog.cpp b/editor/input_event_configuration_dialog.cpp
index a2aeeb11bd..c60197b96b 100644
--- a/editor/input_event_configuration_dialog.cpp
+++ b/editor/input_event_configuration_dialog.cpp
@@ -551,18 +551,18 @@ void InputEventConfigurationDialog::_input_list_item_selected() {
}
void InputEventConfigurationDialog::_device_selection_changed(int p_option_button_index) {
- // Option index 0 corresponds to "All Devices" (value of -3).
- // Otherwise subtract 1 as option index 1 corresponds to device 0, etc...
- event->set_device(p_option_button_index == 0 ? InputEvent::DEVICE_ID_ALL_DEVICES : p_option_button_index - 1);
+ // Subtract 1 as option index 0 corresponds to "All Devices" (value of -1)
+ // and option index 1 corresponds to device 0, etc...
+ event->set_device(p_option_button_index - 1);
event_as_text->set_text(EventListenerLineEdit::get_event_text(event, true));
}
void InputEventConfigurationDialog::_set_current_device(int p_device) {
- device_id_option->select(p_device == InputEvent::DEVICE_ID_ALL_DEVICES ? 0 : p_device + 1);
+ device_id_option->select(p_device + 1);
}
int InputEventConfigurationDialog::_get_current_device() const {
- return device_id_option->get_selected() == 0 ? InputEvent::DEVICE_ID_ALL_DEVICES : device_id_option->get_selected() - 1;
+ return device_id_option->get_selected() - 1;
}
void InputEventConfigurationDialog::_notification(int p_what) {
@@ -705,12 +705,11 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() {
device_id_option = memnew(OptionButton);
device_id_option->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- device_id_option->add_item(EventListenerLineEdit::get_device_string(InputEvent::DEVICE_ID_ALL_DEVICES));
- for (int i = 0; i < 8; i++) {
+ for (int i = -1; i < 8; i++) {
device_id_option->add_item(EventListenerLineEdit::get_device_string(i));
}
device_id_option->connect(SceneStringName(item_selected), callable_mp(this, &InputEventConfigurationDialog::_device_selection_changed));
- _set_current_device(InputEvent::DEVICE_ID_ALL_DEVICES);
+ _set_current_device(InputMap::ALL_DEVICES);
device_container->add_child(device_id_option);
device_container->hide();
diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp
index 921467ccbc..7b2e6e81ee 100644
--- a/editor/localization_editor.cpp
+++ b/editor/localization_editor.cpp
@@ -441,7 +441,7 @@ void LocalizationEditor::_filesystem_files_moved(const String &p_old_file, const
bool remapped_files_updated = false;
for (int j = 0; j < remapped_files.size(); j++) {
- int splitter_pos = remapped_files[j].rfind(":");
+ int splitter_pos = remapped_files[j].rfind_char(':');
String res_path = remapped_files[j].substr(0, splitter_pos);
if (res_path == p_old_file) {
@@ -482,7 +482,7 @@ void LocalizationEditor::_filesystem_file_removed(const String &p_file) {
for (int i = 0; i < remap_keys.size() && !remaps_changed; i++) {
PackedStringArray remapped_files = remaps[remap_keys[i]];
for (int j = 0; j < remapped_files.size() && !remaps_changed; j++) {
- int splitter_pos = remapped_files[j].rfind(":");
+ int splitter_pos = remapped_files[j].rfind_char(':');
String res_path = remapped_files[j].substr(0, splitter_pos);
remaps_changed = p_file == res_path;
if (remaps_changed) {
@@ -567,7 +567,7 @@ void LocalizationEditor::update_translations() {
PackedStringArray selected = remaps[keys[i]];
for (int j = 0; j < selected.size(); j++) {
const String &s2 = selected[j];
- int qp = s2.rfind(":");
+ int qp = s2.rfind_char(':');
String path = s2.substr(0, qp);
String locale = s2.substr(qp + 1, s2.length());
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index eef890d013..096e92e235 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -45,6 +45,7 @@
#include "scene/3d/skeleton_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/gui/check_box.h"
+#include "scene/gui/grid_container.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/option_button.h"
#include "scene/gui/panel.h"
@@ -1397,32 +1398,30 @@ bool EditorInspectorPluginAnimationNodeAnimation::parse_property(Object *p_objec
}
AnimationNodeAnimationEditorDialog::AnimationNodeAnimationEditorDialog() {
- set_title(TTR("Select Markers..."));
- VBoxContainer *vbox = memnew(VBoxContainer);
- add_child(vbox);
- vbox->set_offsets_preset(Control::PRESET_FULL_RECT);
-
- HBoxContainer *container_start = memnew(HBoxContainer);
- vbox->add_child(container_start);
- Label *label_start = memnew(Label);
- container_start->add_child(label_start);
+ set_title(TTR("Select Markers"));
+
+ GridContainer *grid = memnew(GridContainer);
+ grid->set_columns(2);
+ grid->set_offsets_preset(Control::PRESET_FULL_RECT);
+ add_child(grid);
+
+ Label *label_start = memnew(Label(TTR("Start Marker")));
+ grid->add_child(label_start);
label_start->set_h_size_flags(Control::SIZE_EXPAND_FILL);
label_start->set_stretch_ratio(1);
- label_start->set_text(TTR("Start Marker"));
select_start = memnew(OptionButton);
- container_start->add_child(select_start);
+ select_start->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
+ grid->add_child(select_start);
select_start->set_h_size_flags(Control::SIZE_EXPAND_FILL);
select_start->set_stretch_ratio(2);
- HBoxContainer *container_end = memnew(HBoxContainer);
- vbox->add_child(container_end);
- Label *label_end = memnew(Label);
- container_end->add_child(label_end);
+ Label *label_end = memnew(Label(TTR("End Marker")));
+ grid->add_child(label_end);
label_end->set_h_size_flags(Control::SIZE_EXPAND_FILL);
label_end->set_stretch_ratio(1);
- label_end->set_text(TTR("End Marker"));
select_end = memnew(OptionButton);
- container_end->add_child(select_end);
+ select_end->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
+ grid->add_child(select_end);
select_end->set_h_size_flags(Control::SIZE_EXPAND_FILL);
select_end->set_stretch_ratio(2);
}
diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp
index 4e8a1bd89b..46410b581e 100644
--- a/editor/plugins/animation_library_editor.cpp
+++ b/editor/plugins/animation_library_editor.cpp
@@ -30,7 +30,12 @@
#include "animation_library_editor.h"
+#include "core/string/print_string.h"
+#include "core/string/ustring.h"
+#include "core/templates/vector.h"
+#include "core/variant/variant.h"
#include "editor/editor_node.h"
+#include "editor/editor_paths.h"
#include "editor/editor_settings.h"
#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
@@ -518,6 +523,8 @@ void AnimationLibraryEditor::_item_renamed() {
if (restore_text) {
ti->set_text(0, old_text);
}
+
+ _save_mixer_lib_folding(ti);
}
void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int p_id, MouseButton p_button) {
@@ -670,6 +677,8 @@ void AnimationLibraryEditor::update_tree() {
TreeItem *root = tree->create_item();
List<StringName> libs;
+ Vector<uint64_t> collapsed_lib_ids = _load_mixer_libs_folding();
+
mixer->get_animation_library_list(&libs);
for (const StringName &K : libs) {
@@ -759,12 +768,203 @@ void AnimationLibraryEditor::update_tree() {
anitem->set_text(1, anim_path.get_file());
}
}
+
anitem->add_button(1, get_editor_theme_icon("Save"), ANIM_BUTTON_FILE, animation_library_is_foreign, TTR("Save animation to resource on disk."));
anitem->add_button(1, get_editor_theme_icon("Remove"), ANIM_BUTTON_DELETE, animation_library_is_foreign, TTR("Remove animation from Library."));
+
+ for (const uint64_t &lib_id : collapsed_lib_ids) {
+ Object *lib_obj = ObjectDB::get_instance(ObjectID(lib_id));
+ AnimationLibrary *cur_lib = Object::cast_to<AnimationLibrary>(lib_obj);
+ StringName M = mixer->get_animation_library_name(cur_lib);
+
+ if (M == K) {
+ libitem->set_collapsed_recursive(true);
+ }
+ }
}
}
}
+void AnimationLibraryEditor::_save_mixer_lib_folding(TreeItem *p_item) {
+ //Check if ti is a library or animation
+ if (p_item->get_parent()->get_parent() != nullptr) {
+ return;
+ }
+
+ Ref<ConfigFile> config;
+ config.instantiate();
+
+ String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("lib_folding.cfg");
+ Error err = config->load(path);
+ if (err != OK && err != ERR_FILE_NOT_FOUND) {
+ ERR_PRINT("Error loading lib_folding.cfg: " + itos(err));
+ }
+
+ // Get unique identifier for this scene+mixer combination
+ String md = (mixer->get_tree()->get_edited_scene_root()->get_scene_file_path() + mixer->get_path()).md5_text();
+
+ PackedStringArray collapsed_lib_names;
+ PackedStringArray collapsed_lib_ids;
+
+ if (config->has_section(md)) {
+ collapsed_lib_names = String(config->get_value(md, "folding")).split("\n");
+ collapsed_lib_ids = String(config->get_value(md, "id")).split("\n");
+ }
+
+ String lib_name = p_item->get_text(0);
+
+ // Get library reference and check validity
+ Ref<AnimationLibrary> al;
+ uint64_t lib_id = 0;
+
+ if (mixer->has_animation_library(lib_name)) {
+ al = mixer->get_animation_library(lib_name);
+ ERR_FAIL_COND(al.is_null());
+ lib_id = uint64_t(al->get_instance_id());
+ } else {
+ ERR_PRINT("Library not found: " + lib_name);
+ }
+
+ int at = collapsed_lib_names.find(lib_name);
+ if (p_item->is_collapsed()) {
+ if (at != -1) {
+ //Entry exists and needs updating
+ collapsed_lib_ids.set(at, String::num_int64(lib_id + INT64_MIN));
+ } else {
+ //Check if it's a rename
+ int id_at = collapsed_lib_ids.find(String::num_int64(lib_id + INT64_MIN));
+ if (id_at != -1) {
+ //It's actually a rename
+ collapsed_lib_names.set(id_at, lib_name);
+ } else {
+ //It's a new entry
+ collapsed_lib_names.append(lib_name);
+ collapsed_lib_ids.append(String::num_int64(lib_id + INT64_MIN));
+ }
+ }
+ } else {
+ if (at != -1) {
+ collapsed_lib_names.remove_at(at);
+ collapsed_lib_ids.remove_at(at);
+ }
+ }
+
+ //Runtime IDs
+ config->set_value(md, "root", uint64_t(mixer->get_tree()->get_edited_scene_root()->get_instance_id()));
+ config->set_value(md, "mixer", uint64_t(mixer->get_instance_id()));
+
+ //Plan B recovery mechanism
+ config->set_value(md, "mixer_signature", _get_mixer_signature());
+
+ //Save folding state as text and runtime ID
+ config->set_value(md, "folding", String("\n").join(collapsed_lib_names));
+ config->set_value(md, "id", String("\n").join(collapsed_lib_ids));
+
+ err = config->save(path);
+ if (err != OK) {
+ ERR_PRINT("Error saving lib_folding.cfg: " + itos(err));
+ }
+}
+
+Vector<uint64_t> AnimationLibraryEditor::_load_mixer_libs_folding() {
+ Ref<ConfigFile> config;
+ config.instantiate();
+
+ String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("lib_folding.cfg");
+ Error err = config->load(path);
+ if (err != OK && err != ERR_FILE_NOT_FOUND) {
+ ERR_PRINT("Error loading lib_folding.cfg: " + itos(err));
+ return Vector<uint64_t>();
+ }
+
+ // Get unique identifier for this scene+mixer combination
+ String md = (mixer->get_tree()->get_edited_scene_root()->get_scene_file_path() + mixer->get_path()).md5_text();
+
+ Vector<uint64_t> collapsed_lib_ids;
+
+ if (config->has_section(md)) {
+ _load_config_libs_folding(collapsed_lib_ids, config.ptr(), md);
+
+ } else {
+ //The scene/mixer combination is no longer valid and we'll try to recover
+ uint64_t current_mixer_id = uint64_t(mixer->get_instance_id());
+ String current_mixer_signature = _get_mixer_signature();
+ List<String> sections;
+ config->get_sections(&sections);
+
+ for (const String &section : sections) {
+ Variant mixer_id = config->get_value(section, "mixer");
+ if ((mixer_id.get_type() == Variant::INT && uint64_t(mixer_id) == current_mixer_id) || config->get_value(section, "mixer_signature") == current_mixer_signature) { // Ensure value exists and is correct type
+ // Found the mixer in a different section!
+ _load_config_libs_folding(collapsed_lib_ids, config.ptr(), section);
+
+ //Cleanup old entry and copy fold data into new one!
+ String collapsed_lib_names_str = String(config->get_value(section, "folding"));
+ String collapsed_lib_ids_str = String(config->get_value(section, "id"));
+ config->erase_section(section);
+
+ config->set_value(md, "root", uint64_t(mixer->get_tree()->get_edited_scene_root()->get_instance_id()));
+ config->set_value(md, "mixer", uint64_t(mixer->get_instance_id()));
+ config->set_value(md, "mixer_signature", _get_mixer_signature());
+ config->set_value(md, "folding", collapsed_lib_names_str);
+ config->set_value(md, "id", collapsed_lib_ids_str);
+
+ err = config->save(path);
+ if (err != OK) {
+ ERR_PRINT("Error saving lib_folding.cfg: " + itos(err));
+ }
+ break;
+ }
+ }
+ }
+
+ return collapsed_lib_ids;
+}
+
+void AnimationLibraryEditor::_load_config_libs_folding(Vector<uint64_t> &p_lib_ids, ConfigFile *p_config, String p_section) {
+ if (uint64_t(p_config->get_value(p_section, "root", 0)) != uint64_t(mixer->get_tree()->get_edited_scene_root()->get_instance_id())) {
+ // Root changed - tries to match by library names
+ PackedStringArray collapsed_lib_names = String(p_config->get_value(p_section, "folding", "")).split("\n");
+ for (const String &lib_name : collapsed_lib_names) {
+ if (mixer->has_animation_library(lib_name)) {
+ p_lib_ids.append(mixer->get_animation_library(lib_name)->get_instance_id());
+ } else {
+ print_line("Can't find ", lib_name, " in mixer");
+ }
+ }
+ } else {
+ // Root same - uses saved instance IDs
+ for (const String &saved_id : String(p_config->get_value(p_section, "id")).split("\n")) {
+ p_lib_ids.append(uint64_t(saved_id.to_int() - INT64_MIN));
+ }
+ }
+}
+
+String AnimationLibraryEditor::_get_mixer_signature() const {
+ String signature = String();
+
+ // Get all libraries sorted for consistency
+ List<StringName> libs;
+ mixer->get_animation_library_list(&libs);
+ libs.sort_custom<StringName::AlphCompare>();
+
+ // Add libraries and their animations to signature
+ for (const StringName &lib_name : libs) {
+ signature += "::" + String(lib_name);
+ Ref<AnimationLibrary> lib = mixer->get_animation_library(lib_name);
+ if (lib.is_valid()) {
+ List<StringName> anims;
+ lib->get_animation_list(&anims);
+ anims.sort_custom<StringName::AlphCompare>();
+ for (const StringName &anim_name : anims) {
+ signature += "," + String(anim_name);
+ }
+ }
+ }
+
+ return signature.md5_text();
+}
+
void AnimationLibraryEditor::show_dialog() {
update_tree();
popup_centered_ratio(0.5);
@@ -855,11 +1055,12 @@ AnimationLibraryEditor::AnimationLibraryEditor() {
tree->set_column_custom_minimum_width(1, EDSCALE * 250);
tree->set_column_expand(1, false);
tree->set_hide_root(true);
- tree->set_hide_folding(true);
+ tree->set_hide_folding(false);
tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
tree->connect("item_edited", callable_mp(this, &AnimationLibraryEditor::_item_renamed));
tree->connect("button_clicked", callable_mp(this, &AnimationLibraryEditor::_button_pressed));
+ tree->connect("item_collapsed", callable_mp(this, &AnimationLibraryEditor::_save_mixer_lib_folding));
file_popup = memnew(PopupMenu);
add_child(file_popup);
diff --git a/editor/plugins/animation_library_editor.h b/editor/plugins/animation_library_editor.h
index beb34c6343..c4ad1684a6 100644
--- a/editor/plugins/animation_library_editor.h
+++ b/editor/plugins/animation_library_editor.h
@@ -31,6 +31,8 @@
#ifndef ANIMATION_LIBRARY_EDITOR_H
#define ANIMATION_LIBRARY_EDITOR_H
+#include "core/io/config_file.h"
+#include "core/templates/vector.h"
#include "editor/animation_track_editor.h"
#include "editor/plugins/editor_plugin.h"
#include "scene/animation/animation_mixer.h"
@@ -103,6 +105,11 @@ class AnimationLibraryEditor : public AcceptDialog {
void _load_file(const String &p_path);
void _load_files(const PackedStringArray &p_paths);
+ void _save_mixer_lib_folding(TreeItem *p_item);
+ Vector<uint64_t> _load_mixer_libs_folding();
+ void _load_config_libs_folding(Vector<uint64_t> &p_lib_ids, ConfigFile *p_config, String p_section);
+ String _get_mixer_signature() const;
+
void _item_renamed();
void _button_pressed(TreeItem *p_item, int p_column, int p_id, MouseButton p_button);
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index d10daa2bfc..8526150e0c 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -917,7 +917,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
}
if (state_machine_draw->has_focus()) {
- state_machine_draw->draw_rect(Rect2(Point2(), state_machine_draw->get_size()), theme_cache.highlight_color, false);
+ state_machine_draw->draw_rect(Rect2(Point2(), state_machine_draw->get_size()), theme_cache.focus_color, false);
}
int sep = 3 * EDSCALE;
@@ -1642,6 +1642,7 @@ void AnimationNodeStateMachineEditor::_bind_methods() {
BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, transition_icon_disabled_color, "transition_icon_disabled_color", "GraphStateMachine");
BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, highlight_color, "highlight_color", "GraphStateMachine");
BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, highlight_disabled_color, "highlight_disabled_color", "GraphStateMachine");
+ BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, focus_color, "focus_color", "GraphStateMachine");
BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, guideline_color, "guideline_color", "GraphStateMachine");
BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icons[0], "TransitionImmediateBig", "EditorIcons");
diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h
index eb623a147d..0b6320f0ce 100644
--- a/editor/plugins/animation_state_machine_editor.h
+++ b/editor/plugins/animation_state_machine_editor.h
@@ -117,6 +117,7 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
Color transition_icon_disabled_color;
Color highlight_color;
Color highlight_disabled_color;
+ Color focus_color;
Color guideline_color;
Ref<Texture2D> transition_icons[6]{};
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index 8db106da07..7c9c003ea1 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -907,7 +907,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons
for (int i = 0; i < headers.size(); i++) {
if (headers[i].findn("ETag:") == 0) { // Save etag
String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().path_join("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
- String new_etag = headers[i].substr(headers[i].find(":") + 1, headers[i].length()).strip_edges();
+ String new_etag = headers[i].substr(headers[i].find_char(':') + 1, headers[i].length()).strip_edges();
Ref<FileAccess> file = FileAccess::open(cache_filename_base + ".etag", FileAccess::WRITE);
if (file.is_valid()) {
file->store_line(new_etag);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 62793fbcb5..f73867575d 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -1930,37 +1930,50 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
// Drag resize handles
if (drag_type == DRAG_NONE) {
- if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && ((b->is_alt_pressed() && b->is_command_or_control_pressed()) || tool == TOOL_SCALE)) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() &&
+ ((tool == TOOL_SELECT && b->is_alt_pressed() && b->is_command_or_control_pressed()) || tool == TOOL_SCALE)) {
bool has_locked_items = false;
List<CanvasItem *> selection = _get_edited_canvas_items(false, true, &has_locked_items);
- if (selection.size() == 1) {
+
+ // Remove non-movable nodes.
+ for (CanvasItem *ci : selection) {
+ if (!_is_node_movable(ci, true)) {
+ selection.erase(ci);
+ }
+ }
+
+ if (!selection.is_empty()) {
CanvasItem *ci = selection.front()->get();
- if (_is_node_movable(ci)) {
- Transform2D xform = transform * ci->get_global_transform_with_canvas();
- Transform2D unscaled_transform = (xform * ci->get_transform().affine_inverse() * ci->_edit_get_transform()).orthonormalized();
- Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
+ Transform2D edit_transform;
+ if (!Math::is_inf(temp_pivot.x) || !Math::is_inf(temp_pivot.y)) {
+ edit_transform = Transform2D(ci->_edit_get_rotation(), temp_pivot);
+ } else {
+ edit_transform = ci->_edit_get_transform();
+ }
- drag_type = DRAG_SCALE_BOTH;
+ Transform2D xform = transform * ci->get_global_transform_with_canvas();
+ Transform2D unscaled_transform = (xform * ci->get_transform().affine_inverse() * edit_transform).orthonormalized();
+ Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
- if (show_transformation_gizmos) {
- Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE);
- Rect2 x_handle_rect = Rect2(scale_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
- if (x_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) {
- drag_type = DRAG_SCALE_X;
- }
- Rect2 y_handle_rect = Rect2(-5 * EDSCALE, scale_factor.y * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
- if (y_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) {
- drag_type = DRAG_SCALE_Y;
- }
- }
+ drag_type = DRAG_SCALE_BOTH;
- drag_from = transform.affine_inverse().xform(b->get_position());
- drag_selection = List<CanvasItem *>();
- drag_selection.push_back(ci);
- _save_canvas_item_state(drag_selection);
- return true;
+ if (show_transformation_gizmos) {
+ Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE);
+ Rect2 x_handle_rect = Rect2(scale_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
+ if (x_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) {
+ drag_type = DRAG_SCALE_X;
+ }
+ Rect2 y_handle_rect = Rect2(-5 * EDSCALE, scale_factor.y * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
+ if (y_handle_rect.has_point(simple_xform.affine_inverse().xform(b->get_position()))) {
+ drag_type = DRAG_SCALE_Y;
+ }
}
+
+ drag_from = transform.affine_inverse().xform(b->get_position());
+ drag_selection = selection;
+ _save_canvas_item_state(drag_selection);
+ return true;
} else {
if (has_locked_items) {
EditorToaster::get_singleton()->popup_str(TTR(locked_transform_warning), EditorToaster::SEVERITY_WARNING);
@@ -1968,66 +1981,86 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
return has_locked_items;
}
}
- }
-
- if (drag_type == DRAG_SCALE_BOTH || drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y) {
+ } else if (drag_type == DRAG_SCALE_BOTH || drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y) {
// Resize the node
if (m.is_valid()) {
_restore_canvas_item_state(drag_selection);
- CanvasItem *ci = drag_selection.front()->get();
drag_to = transform.affine_inverse().xform(m->get_position());
- Transform2D parent_xform = ci->get_global_transform_with_canvas() * ci->get_transform().affine_inverse();
- Transform2D unscaled_transform = (transform * parent_xform * ci->_edit_get_transform()).orthonormalized();
- Transform2D simple_xform = (viewport->get_transform() * unscaled_transform).affine_inverse() * transform;
+ Size2 scale_max;
+ if (drag_type != DRAG_SCALE_BOTH) {
+ for (CanvasItem *ci : drag_selection) {
+ scale_max = scale_max.max(ci->_edit_get_scale());
+ }
+ }
- bool uniform = m->is_shift_pressed();
- bool is_ctrl = m->is_command_or_control_pressed();
+ Transform2D edit_transform;
+ bool using_temp_pivot = !Math::is_inf(temp_pivot.x) || !Math::is_inf(temp_pivot.y);
+ if (using_temp_pivot) {
+ edit_transform = Transform2D(drag_selection.front()->get()->_edit_get_rotation(), temp_pivot);
+ } else {
+ edit_transform = drag_selection.front()->get()->_edit_get_transform();
+ }
+ for (CanvasItem *ci : drag_selection) {
+ Transform2D parent_xform = ci->get_global_transform_with_canvas() * ci->get_transform().affine_inverse();
+ Transform2D unscaled_transform = (transform * parent_xform * edit_transform).orthonormalized();
+ Transform2D simple_xform = (viewport->get_transform() * unscaled_transform).affine_inverse() * transform;
- Point2 drag_from_local = simple_xform.xform(drag_from);
- Point2 drag_to_local = simple_xform.xform(drag_to);
- Point2 offset = drag_to_local - drag_from_local;
+ bool uniform = m->is_shift_pressed();
+ bool is_ctrl = m->is_command_or_control_pressed();
- Size2 scale = ci->_edit_get_scale();
- Size2 original_scale = scale;
- real_t ratio = scale.y / scale.x;
- if (drag_type == DRAG_SCALE_BOTH) {
- Size2 scale_factor = drag_to_local / drag_from_local;
- if (uniform) {
- scale *= (scale_factor.x + scale_factor.y) / 2.0;
- } else {
- scale *= scale_factor;
- }
- } else {
- Size2 scale_factor = Vector2(offset.x, -offset.y) / SCALE_HANDLE_DISTANCE;
- Size2 parent_scale = parent_xform.get_scale();
- scale_factor *= Vector2(1.0 / parent_scale.x, 1.0 / parent_scale.y);
+ Point2 drag_from_local = simple_xform.xform(drag_from);
+ Point2 drag_to_local = simple_xform.xform(drag_to);
+ Point2 offset = drag_to_local - drag_from_local;
- if (drag_type == DRAG_SCALE_X) {
- scale.x += scale_factor.x;
+ Size2 scale = ci->_edit_get_scale();
+ Size2 original_scale = scale;
+ real_t ratio = scale.y / scale.x;
+ if (drag_type == DRAG_SCALE_BOTH) {
+ Size2 scale_factor = drag_to_local / drag_from_local;
if (uniform) {
- scale.y = scale.x * ratio;
+ scale *= (scale_factor.x + scale_factor.y) / 2.0;
+ } else {
+ scale *= scale_factor;
}
- } else if (drag_type == DRAG_SCALE_Y) {
- scale.y -= scale_factor.y;
- if (uniform) {
- scale.x = scale.y / ratio;
+ } else {
+ Size2 scale_factor = Vector2(offset.x, -offset.y) / SCALE_HANDLE_DISTANCE;
+ Size2 parent_scale = parent_xform.get_scale();
+ // Take into account the biggest scale, so all nodes are scaled uniformly.
+ scale_factor *= Vector2(1.0 / parent_scale.x, 1.0 / parent_scale.y) / (scale_max / original_scale);
+
+ if (drag_type == DRAG_SCALE_X) {
+ scale.x += scale_factor.x;
+ if (uniform) {
+ scale.y = scale.x * ratio;
+ }
+ } else if (drag_type == DRAG_SCALE_Y) {
+ scale.y -= scale_factor.y;
+ if (uniform) {
+ scale.x = scale.y / ratio;
+ }
}
}
- }
- if (snap_scale && !is_ctrl) {
- if (snap_relative) {
- scale.x = original_scale.x * (roundf((scale.x / original_scale.x) / snap_scale_step) * snap_scale_step);
- scale.y = original_scale.y * (roundf((scale.y / original_scale.y) / snap_scale_step) * snap_scale_step);
- } else {
- scale.x = roundf(scale.x / snap_scale_step) * snap_scale_step;
- scale.y = roundf(scale.y / snap_scale_step) * snap_scale_step;
+ if (snap_scale && !is_ctrl) {
+ if (snap_relative) {
+ scale.x = original_scale.x * (Math::round((scale.x / original_scale.x) / snap_scale_step) * snap_scale_step);
+ scale.y = original_scale.y * (Math::round((scale.y / original_scale.y) / snap_scale_step) * snap_scale_step);
+ } else {
+ scale.x = Math::round(scale.x / snap_scale_step) * snap_scale_step;
+ scale.y = Math::round(scale.y / snap_scale_step) * snap_scale_step;
+ }
+ }
+
+ ci->_edit_set_scale(scale);
+
+ if (using_temp_pivot) {
+ Point2 ci_origin = ci->_edit_get_transform().get_origin();
+ ci->_edit_set_position(ci_origin + (ci_origin - temp_pivot) * ((scale - original_scale) / original_scale));
}
}
- ci->_edit_set_scale(scale);
return true;
}
@@ -2075,7 +2108,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
if (drag_type == DRAG_NONE) {
//Start moving the nodes
if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed()) {
- if ((b->is_alt_pressed() && !b->is_command_or_control_pressed()) || tool == TOOL_MOVE) {
+ if ((tool == TOOL_SELECT && b->is_alt_pressed() && !b->is_command_or_control_pressed()) || tool == TOOL_MOVE) {
bool has_locked_items = false;
List<CanvasItem *> selection = _get_edited_canvas_items(false, true, &has_locked_items);
@@ -2135,7 +2168,7 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
}
Point2 drag_delta = drag_to - drag_from;
- if (drag_selection.size() == 1 && (drag_type == DRAG_MOVE_X || drag_type == DRAG_MOVE_Y)) {
+ if (drag_type == DRAG_MOVE_X || drag_type == DRAG_MOVE_Y) {
const CanvasItem *selected = drag_selection.front()->get();
Transform2D parent_xform = selected->get_global_transform_with_canvas() * selected->get_transform().affine_inverse();
Transform2D unscaled_transform = (transform * parent_xform * selected->_edit_get_transform()).orthonormalized();
@@ -3468,16 +3501,14 @@ void CanvasItemEditor::_draw_selection() {
Ref<Texture2D> previous_position_icon = get_editor_theme_icon(SNAME("EditorPositionPrevious"));
RID vp_ci = viewport->get_canvas_item();
-
List<CanvasItem *> selection = _get_edited_canvas_items(true, false);
-
bool single = selection.size() == 1;
+ bool transform_tool = tool == TOOL_SELECT || tool == TOOL_MOVE || tool == TOOL_SCALE || tool == TOOL_ROTATE || tool == TOOL_EDIT_PIVOT;
+
for (CanvasItem *E : selection) {
CanvasItem *ci = Object::cast_to<CanvasItem>(E);
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci);
- bool item_locked = ci->has_meta("_edit_lock_");
-
// Draw the previous position if we are dragging the node
if (show_helpers &&
(drag_type == DRAG_MOVE || drag_type == DRAG_ROTATE ||
@@ -3502,6 +3533,7 @@ void CanvasItemEditor::_draw_selection() {
}
}
+ bool item_locked = ci->has_meta("_edit_lock_");
Transform2D xform = transform * ci->get_global_transform_with_canvas();
// Draw the selected items position / surrounding boxes
@@ -3531,7 +3563,7 @@ void CanvasItemEditor::_draw_selection() {
viewport->draw_set_transform_matrix(viewport->get_transform());
}
- if (single && !item_locked && (tool == TOOL_SELECT || tool == TOOL_MOVE || tool == TOOL_SCALE || tool == TOOL_ROTATE || tool == TOOL_EDIT_PIVOT)) { //kind of sucks
+ if (single && !item_locked && transform_tool) {
// Draw the pivot
if (ci->_edit_use_pivot()) {
// Draw the node's pivot
@@ -3574,73 +3606,88 @@ void CanvasItemEditor::_draw_selection() {
select_handle->draw(vp_ci, (ofs - (select_handle->get_size() / 2)).floor());
}
}
+ }
+ }
- // Draw the move handles
- bool is_ctrl = Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL);
- bool is_alt = Input::get_singleton()->is_key_pressed(Key::ALT);
- if (tool == TOOL_MOVE && show_transformation_gizmos) {
- if (_is_node_movable(ci)) {
- Transform2D unscaled_transform = (xform * ci->get_transform().affine_inverse() * ci->_edit_get_transform()).orthonormalized();
- Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
+ // Remove non-movable nodes.
+ for (CanvasItem *ci : selection) {
+ if (!_is_node_movable(ci)) {
+ selection.erase(ci);
+ }
+ }
- Size2 move_factor = Size2(MOVE_HANDLE_DISTANCE, MOVE_HANDLE_DISTANCE);
- viewport->draw_set_transform_matrix(simple_xform);
+ if (!selection.is_empty() && transform_tool && show_transformation_gizmos) {
+ CanvasItem *ci = selection.front()->get();
- Vector<Point2> points = {
- Vector2(move_factor.x * EDSCALE, 5 * EDSCALE),
- Vector2(move_factor.x * EDSCALE, -5 * EDSCALE),
- Vector2((move_factor.x + 10) * EDSCALE, 0)
- };
+ Transform2D xform = transform * ci->get_global_transform_with_canvas();
+ bool is_ctrl = Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL);
+ bool is_alt = Input::get_singleton()->is_key_pressed(Key::ALT);
- viewport->draw_colored_polygon(points, get_theme_color(SNAME("axis_x_color"), EditorStringName(Editor)));
- viewport->draw_line(Point2(), Point2(move_factor.x * EDSCALE, 0), get_theme_color(SNAME("axis_x_color"), EditorStringName(Editor)), Math::round(EDSCALE));
+ // Draw the move handles.
+ if ((tool == TOOL_SELECT && is_alt && !is_ctrl) || tool == TOOL_MOVE) {
+ Transform2D unscaled_transform = (xform * ci->get_transform().affine_inverse() * ci->_edit_get_transform()).orthonormalized();
+ Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
- points.clear();
- points.push_back(Vector2(5 * EDSCALE, move_factor.y * EDSCALE));
- points.push_back(Vector2(-5 * EDSCALE, move_factor.y * EDSCALE));
- points.push_back(Vector2(0, (move_factor.y + 10) * EDSCALE));
+ Size2 move_factor = Size2(MOVE_HANDLE_DISTANCE, MOVE_HANDLE_DISTANCE);
+ viewport->draw_set_transform_matrix(simple_xform);
- viewport->draw_colored_polygon(points, get_theme_color(SNAME("axis_y_color"), EditorStringName(Editor)));
- viewport->draw_line(Point2(), Point2(0, move_factor.y * EDSCALE), get_theme_color(SNAME("axis_y_color"), EditorStringName(Editor)), Math::round(EDSCALE));
+ Vector<Point2> points = {
+ Vector2(move_factor.x * EDSCALE, 5 * EDSCALE),
+ Vector2(move_factor.x * EDSCALE, -5 * EDSCALE),
+ Vector2((move_factor.x + 10) * EDSCALE, 0)
+ };
- viewport->draw_set_transform_matrix(viewport->get_transform());
- }
- }
+ viewport->draw_colored_polygon(points, get_theme_color(SNAME("axis_x_color"), EditorStringName(Editor)));
+ viewport->draw_line(Point2(), Point2(move_factor.x * EDSCALE, 0), get_theme_color(SNAME("axis_x_color"), EditorStringName(Editor)), Math::round(EDSCALE));
- // Draw the rescale handles
- if (show_transformation_gizmos && ((is_alt && is_ctrl) || tool == TOOL_SCALE || drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y)) {
- if (_is_node_movable(ci)) {
- Transform2D unscaled_transform = (xform * ci->get_transform().affine_inverse() * ci->_edit_get_transform()).orthonormalized();
- Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
+ points.clear();
+ points.push_back(Vector2(5 * EDSCALE, move_factor.y * EDSCALE));
+ points.push_back(Vector2(-5 * EDSCALE, move_factor.y * EDSCALE));
+ points.push_back(Vector2(0, (move_factor.y + 10) * EDSCALE));
- Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE);
- bool uniform = Input::get_singleton()->is_key_pressed(Key::SHIFT);
- Point2 offset = (simple_xform.affine_inverse().xform(drag_to) - simple_xform.affine_inverse().xform(drag_from)) * zoom;
+ viewport->draw_colored_polygon(points, get_theme_color(SNAME("axis_y_color"), EditorStringName(Editor)));
+ viewport->draw_line(Point2(), Point2(0, move_factor.y * EDSCALE), get_theme_color(SNAME("axis_y_color"), EditorStringName(Editor)), Math::round(EDSCALE));
- if (drag_type == DRAG_SCALE_X) {
- scale_factor.x += offset.x;
- if (uniform) {
- scale_factor.y += offset.x;
- }
- } else if (drag_type == DRAG_SCALE_Y) {
- scale_factor.y += offset.y;
- if (uniform) {
- scale_factor.x += offset.y;
- }
- }
+ viewport->draw_set_transform_matrix(viewport->get_transform());
+ }
- viewport->draw_set_transform_matrix(simple_xform);
- Rect2 x_handle_rect = Rect2(scale_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
- viewport->draw_rect(x_handle_rect, get_theme_color(SNAME("axis_x_color"), EditorStringName(Editor)));
- viewport->draw_line(Point2(), Point2(scale_factor.x * EDSCALE, 0), get_theme_color(SNAME("axis_x_color"), EditorStringName(Editor)), Math::round(EDSCALE));
+ // Draw the rescale handles.
+ if ((tool == TOOL_SELECT && is_alt && is_ctrl) || tool == TOOL_SCALE || drag_type == DRAG_SCALE_X || drag_type == DRAG_SCALE_Y) {
+ Transform2D edit_transform;
+ if (!Math::is_inf(temp_pivot.x) || !Math::is_inf(temp_pivot.y)) {
+ edit_transform = Transform2D(ci->_edit_get_rotation(), temp_pivot);
+ } else {
+ edit_transform = ci->_edit_get_transform();
+ }
+ Transform2D unscaled_transform = (xform * ci->get_transform().affine_inverse() * edit_transform).orthonormalized();
+ Transform2D simple_xform = viewport->get_transform() * unscaled_transform;
- Rect2 y_handle_rect = Rect2(-5 * EDSCALE, scale_factor.y * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
- viewport->draw_rect(y_handle_rect, get_theme_color(SNAME("axis_y_color"), EditorStringName(Editor)));
- viewport->draw_line(Point2(), Point2(0, scale_factor.y * EDSCALE), get_theme_color(SNAME("axis_y_color"), EditorStringName(Editor)), Math::round(EDSCALE));
+ Size2 scale_factor = Size2(SCALE_HANDLE_DISTANCE, SCALE_HANDLE_DISTANCE);
+ bool uniform = Input::get_singleton()->is_key_pressed(Key::SHIFT);
+ Point2 offset = (simple_xform.affine_inverse().xform(drag_to) - simple_xform.affine_inverse().xform(drag_from)) * zoom;
- viewport->draw_set_transform_matrix(viewport->get_transform());
+ if (drag_type == DRAG_SCALE_X) {
+ scale_factor.x += offset.x;
+ if (uniform) {
+ scale_factor.y += offset.x;
+ }
+ } else if (drag_type == DRAG_SCALE_Y) {
+ scale_factor.y += offset.y;
+ if (uniform) {
+ scale_factor.x += offset.y;
}
}
+
+ viewport->draw_set_transform_matrix(simple_xform);
+ Rect2 x_handle_rect = Rect2(scale_factor.x * EDSCALE, -5 * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
+ viewport->draw_rect(x_handle_rect, get_theme_color(SNAME("axis_x_color"), EditorStringName(Editor)));
+ viewport->draw_line(Point2(), Point2(scale_factor.x * EDSCALE, 0), get_theme_color(SNAME("axis_x_color"), EditorStringName(Editor)), Math::round(EDSCALE));
+
+ Rect2 y_handle_rect = Rect2(-5 * EDSCALE, scale_factor.y * EDSCALE, 10 * EDSCALE, 10 * EDSCALE);
+ viewport->draw_rect(y_handle_rect, get_theme_color(SNAME("axis_y_color"), EditorStringName(Editor)));
+ viewport->draw_line(Point2(), Point2(0, scale_factor.y * EDSCALE), get_theme_color(SNAME("axis_y_color"), EditorStringName(Editor)), Math::round(EDSCALE));
+
+ viewport->draw_set_transform_matrix(viewport->get_transform());
}
}
@@ -3865,7 +3912,7 @@ void CanvasItemEditor::_draw_message() {
Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));
int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));
- Point2 msgpos = Point2(RULER_WIDTH + 5 * EDSCALE, viewport->get_size().y - 20 * EDSCALE);
+ Point2 msgpos = Point2(RULER_WIDTH + 10 * EDSCALE, viewport->get_size().y - 14 * EDSCALE);
viewport->draw_string(font, msgpos + Point2(1, 1), message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(0, 0, 0, 0.8));
viewport->draw_string(font, msgpos + Point2(-1, -1), message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(0, 0, 0, 0.8));
viewport->draw_string(font, msgpos, message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(1, 1, 1, 1));
@@ -5356,7 +5403,7 @@ CanvasItemEditor::CanvasItemEditor() {
main_menu_hbox->add_child(pivot_button);
pivot_button->set_toggle_mode(true);
pivot_button->connect(SceneStringName(pressed), callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_EDIT_PIVOT));
- pivot_button->set_tooltip_text(TTR("Click to change object's rotation pivot.") + "\n" + TTR("Shift: Set temporary rotation pivot.") + "\n" + TTR("Click this button while holding Shift to put the temporary rotation pivot in the center of the selected nodes."));
+ pivot_button->set_tooltip_text(TTR("Click to change object's pivot.") + "\n" + TTR("Shift: Set temporary pivot.") + "\n" + TTR("Click this button while holding Shift to put the temporary pivot in the center of the selected nodes."));
pan_button = memnew(Button);
pan_button->set_theme_type_variation("FlatButton");
diff --git a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp
index 573c686d57..b92abbcf79 100644
--- a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp
@@ -49,17 +49,47 @@
CollisionShape3DGizmoPlugin::CollisionShape3DGizmoPlugin() {
helper.instantiate();
- const Color gizmo_color = SceneTree::get_singleton()->get_debug_collisions_color();
- create_material("shape_material", gizmo_color);
- const float gizmo_value = gizmo_color.get_v();
- const Color gizmo_color_disabled = Color(gizmo_value, gizmo_value, gizmo_value, 0.65);
- create_material("shape_material_disabled", gizmo_color_disabled);
+
+ create_collision_material("shape_material", 2.0);
+ create_collision_material("shape_material_arraymesh", 0.0625);
+
+ create_collision_material("shape_material_disabled", 0.0625);
+ create_collision_material("shape_material_arraymesh_disabled", 0.015625);
+
create_handle_material("handles");
}
CollisionShape3DGizmoPlugin::~CollisionShape3DGizmoPlugin() {
}
+void CollisionShape3DGizmoPlugin::create_collision_material(const String &p_name, float p_alpha) {
+ Vector<Ref<StandardMaterial3D>> mats;
+
+ const Color collision_color(1.0, 1.0, 1.0, p_alpha);
+
+ for (int i = 0; i < 4; i++) {
+ bool instantiated = i < 2;
+
+ Ref<StandardMaterial3D> material = memnew(StandardMaterial3D);
+
+ Color color = collision_color;
+ color.a *= instantiated ? 0.25 : 1.0;
+
+ material->set_albedo(color);
+ material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ material->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MIN + 1);
+ material->set_cull_mode(StandardMaterial3D::CULL_BACK);
+ material->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
+ material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
+
+ mats.push_back(material);
+ }
+
+ materials[p_name] = mats;
+}
+
bool CollisionShape3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
return Object::cast_to<CollisionShape3D>(p_spatial) != nullptr;
}
@@ -311,9 +341,20 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
return;
}
- const Ref<Material> material =
+ const Ref<StandardMaterial3D> material =
get_material(!cs->is_disabled() ? "shape_material" : "shape_material_disabled", p_gizmo);
- Ref<Material> handles_material = get_material("handles");
+ const Ref<StandardMaterial3D> material_arraymesh =
+ get_material(!cs->is_disabled() ? "shape_material_arraymesh" : "shape_material_arraymesh_disabled", p_gizmo);
+ const Ref<Material> handles_material = get_material("handles");
+
+ const Color collision_color = cs->is_disabled() ? Color(1.0, 1.0, 1.0, 0.75) : cs->get_debug_color();
+
+ if (cs->get_debug_fill_enabled()) {
+ Ref<ArrayMesh> array_mesh = s->get_debug_arraymesh_faces(collision_color);
+ if (array_mesh.is_valid()) {
+ p_gizmo->add_mesh(array_mesh, material_arraymesh);
+ }
+ }
if (Object::cast_to<SphereShape3D>(*s)) {
Ref<SphereShape3D> sp = s;
@@ -351,7 +392,7 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
collision_segments.push_back(Vector3(b.x, b.y, 0));
}
- p_gizmo->add_lines(points, material);
+ p_gizmo->add_lines(points, material, false, collision_color);
p_gizmo->add_collision_segments(collision_segments);
Vector<Vector3> handles;
handles.push_back(Vector3(r, 0, 0));
@@ -374,7 +415,7 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
const Vector<Vector3> handles = helper->box_get_handles(bs->get_size());
- p_gizmo->add_lines(lines, material);
+ p_gizmo->add_lines(lines, material, false, collision_color);
p_gizmo->add_collision_segments(lines);
p_gizmo->add_handles(handles, handles_material);
}
@@ -412,7 +453,7 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
points.push_back(Vector3(b.y, b.x, 0) + dud);
}
- p_gizmo->add_lines(points, material);
+ p_gizmo->add_lines(points, material, false, collision_color);
Vector<Vector3> collision_segments;
@@ -476,7 +517,7 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
}
- p_gizmo->add_lines(points, material);
+ p_gizmo->add_lines(points, material, false, collision_color);
Vector<Vector3> collision_segments;
@@ -531,7 +572,7 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p.normal * p.d + p.normal * 3
};
- p_gizmo->add_lines(points, material);
+ p_gizmo->add_lines(points, material, false, collision_color);
p_gizmo->add_collision_segments(points);
}
@@ -549,7 +590,7 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
lines.write[i * 2 + 0] = md.vertices[md.edges[i].vertex_a];
lines.write[i * 2 + 1] = md.vertices[md.edges[i].vertex_b];
}
- p_gizmo->add_lines(lines, material);
+ p_gizmo->add_lines(lines, material, false, collision_color);
p_gizmo->add_collision_segments(lines);
}
}
@@ -558,7 +599,7 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
if (Object::cast_to<ConcavePolygonShape3D>(*s)) {
Ref<ConcavePolygonShape3D> cs2 = s;
Ref<ArrayMesh> mesh = cs2->get_debug_mesh();
- p_gizmo->add_mesh(mesh, material);
+ p_gizmo->add_lines(cs2->get_debug_mesh_lines(), material, false, collision_color);
p_gizmo->add_collision_segments(cs2->get_debug_mesh_lines());
}
@@ -569,7 +610,7 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Vector3(),
Vector3(0, 0, rs->get_length())
};
- p_gizmo->add_lines(points, material);
+ p_gizmo->add_lines(points, material, false, collision_color);
p_gizmo->add_collision_segments(points);
Vector<Vector3> handles;
handles.push_back(Vector3(0, 0, rs->get_length()));
@@ -579,7 +620,7 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
if (Object::cast_to<HeightMapShape3D>(*s)) {
Ref<HeightMapShape3D> hms = s;
- Ref<ArrayMesh> mesh = hms->get_debug_mesh();
- p_gizmo->add_mesh(mesh, material);
+ Vector<Vector3> lines = hms->get_debug_mesh_lines();
+ p_gizmo->add_lines(lines, material, false, collision_color);
}
}
diff --git a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.h b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.h
index 464012acf9..09590fba58 100644
--- a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.h
+++ b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.h
@@ -38,6 +38,8 @@ class Gizmo3DHelper;
class CollisionShape3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(CollisionShape3DGizmoPlugin, EditorNode3DGizmoPlugin);
+ void create_collision_material(const String &p_name, float p_alpha);
+
Ref<Gizmo3DHelper> helper;
public:
diff --git a/editor/plugins/lightmap_gi_editor_plugin.cpp b/editor/plugins/lightmap_gi_editor_plugin.cpp
index 6e5dfd44d4..3f21d5d11c 100644
--- a/editor/plugins/lightmap_gi_editor_plugin.cpp
+++ b/editor/plugins/lightmap_gi_editor_plugin.cpp
@@ -93,10 +93,14 @@ void LightmapGIEditorPlugin::_bake_select_file(const String &p_file) {
file_dialog->popup_file_dialog();
} break;
case LightmapGI::BAKE_ERROR_NO_MESHES: {
- EditorNode::get_singleton()->show_warning(TTR("No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake Light' flag is on."));
+ EditorNode::get_singleton()->show_warning(
+ TTR("No meshes with lightmapping support to bake. Make sure they contain UV2 data and their Global Illumination property is set to Static.") +
+ String::utf8("\n\n• ") + TTR("To import a scene with lightmapping support, set Meshes > Light Baking to Static Lightmaps in the Import dock.") +
+ String::utf8("\n• ") + TTR("To enable lightmapping support on a primitive mesh, edit the PrimitiveMesh resource in the inspector and check Add UV2.") +
+ String::utf8("\n• ") + TTR("To enable lightmapping support on a CSG mesh, select the root CSG node and choose CSG > Bake Mesh Instance at the top of the 3D editor viewport.\nSelect the generated MeshInstance3D node and choose Mesh > Unwrap UV2 for Lightmap/AO at the top of the 3D editor viewport."));
} break;
case LightmapGI::BAKE_ERROR_CANT_CREATE_IMAGE: {
- EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images, make sure path is writable."));
+ EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images. Make sure the lightmap destination path is writable."));
} break;
case LightmapGI::BAKE_ERROR_NO_SCENE_ROOT: {
EditorNode::get_singleton()->show_warning(TTR("No editor scene root found."));
@@ -108,7 +112,7 @@ void LightmapGIEditorPlugin::_bake_select_file(const String &p_file) {
EditorNode::get_singleton()->show_warning(TTR("Maximum texture size is too small for the lightmap images.\nWhile this can be fixed by increasing the maximum texture size, it is recommended you split the scene into more objects instead."));
} break;
case LightmapGI::BAKE_ERROR_LIGHTMAP_TOO_SMALL: {
- EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images. Make sure all meshes selected to bake have `lightmap_size_hint` value set high enough, and `texel_scale` value of LightmapGI is not too low."));
+ EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images. Make sure all meshes to bake have the Lightmap Size Hint property set high enough, and the LightmapGI's Texel Scale value is not too low."));
} break;
case LightmapGI::BAKE_ERROR_ATLAS_TOO_SMALL: {
EditorNode::get_singleton()->show_warning(TTR("Failed fitting a lightmap image into an atlas. This should never happen and should be reported."));
@@ -148,7 +152,7 @@ EditorProgress *LightmapGIEditorPlugin::tmp_progress = nullptr;
bool LightmapGIEditorPlugin::bake_func_step(float p_progress, const String &p_description, void *, bool p_refresh) {
if (!tmp_progress) {
- tmp_progress = memnew(EditorProgress("bake_lightmaps", TTR("Bake Lightmaps"), 1000, false));
+ tmp_progress = memnew(EditorProgress("bake_lightmaps", TTR("Bake Lightmaps"), 1000, true));
ERR_FAIL_NULL_V(tmp_progress, false);
}
return tmp_progress->step(p_description, p_progress * 1000, p_refresh);
diff --git a/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp b/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp
index 360e6b00da..efa98d8e4d 100644
--- a/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp
+++ b/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp
@@ -30,149 +30,506 @@
#include "navigation_obstacle_3d_editor_plugin.h"
-#include "canvas_item_editor_plugin.h"
-#include "core/input/input.h"
-#include "core/io/file_access.h"
+#include "core/config/project_settings.h"
#include "core/math/geometry_2d.h"
-#include "core/os/keyboard.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
-#include "node_3d_editor_plugin.h"
-#include "scene/3d/camera_3d.h"
-#include "scene/gui/separator.h"
+#include "editor/plugins/node_3d_editor_plugin.h"
+#include "scene/3d/navigation_obstacle_3d.h"
+#include "scene/gui/button.h"
+#include "scene/gui/dialogs.h"
+#include "servers/navigation_server_3d.h"
+
+bool NavigationObstacle3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<NavigationObstacle3D>(p_spatial) != nullptr;
+}
+
+String NavigationObstacle3DGizmoPlugin::get_gizmo_name() const {
+ return "NavigationObstacle3D";
+}
+
+void NavigationObstacle3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+ p_gizmo->clear();
+
+ if (!p_gizmo->is_selected() && get_state() == HIDDEN) {
+ return;
+ }
+
+ NavigationObstacle3D *obstacle = Object::cast_to<NavigationObstacle3D>(p_gizmo->get_node_3d());
+
+ if (!obstacle) {
+ return;
+ }
+
+ const Vector<Vector3> &vertices = obstacle->get_vertices();
+ if (vertices.is_empty()) {
+ return;
+ }
+
+ float height = obstacle->get_height();
+
+ const Basis safe_basis = Basis(Vector3(0.0, 1.0, 0.0), obstacle->get_global_rotation().y, obstacle->get_global_basis().get_scale().abs().maxf(0.001));
+ const Basis gbi = obstacle->get_global_basis().inverse();
+ const Basis safe_global_basis = gbi * safe_basis;
+ const int vertex_count = vertices.size();
+
+ Vector<Vector3> lines_mesh_vertices;
+ lines_mesh_vertices.resize(vertex_count * 8);
+ Vector3 *lines_mesh_vertices_ptrw = lines_mesh_vertices.ptrw();
+
+ int vertex_index = 0;
+
+ for (int i = 0; i < vertex_count; i++) {
+ Vector3 point = vertices[i];
+ Vector3 next_point = vertices[(i + 1) % vertex_count];
+
+ Vector3 direction = safe_basis.xform(next_point.direction_to(point));
+ Vector3 arrow_dir = direction.cross(Vector3(0.0, 1.0, 0.0));
+ Vector3 edge_middle = point + ((next_point - point) * 0.5);
+
+ // Ensure vector stays perpendicular even when scaled non-uniformly.
+ lines_mesh_vertices_ptrw[vertex_index++] = safe_global_basis.xform(edge_middle);
+ lines_mesh_vertices_ptrw[vertex_index++] = safe_global_basis.xform(edge_middle) + gbi.xform(arrow_dir) * 0.5;
+
+ lines_mesh_vertices_ptrw[vertex_index++] = safe_global_basis.xform(point);
+ lines_mesh_vertices_ptrw[vertex_index++] = safe_global_basis.xform(next_point);
+
+ lines_mesh_vertices_ptrw[vertex_index++] = safe_global_basis.xform(Vector3(point.x, height, point.z));
+ lines_mesh_vertices_ptrw[vertex_index++] = safe_global_basis.xform(Vector3(next_point.x, height, next_point.z));
+
+ lines_mesh_vertices_ptrw[vertex_index++] = safe_global_basis.xform(point);
+ lines_mesh_vertices_ptrw[vertex_index++] = safe_global_basis.xform(Vector3(point.x, height, point.z));
+ }
+
+ Vector<Vector2> polygon_2d_vertices;
+ polygon_2d_vertices.resize(vertex_count);
+ for (int i = 0; i < vertex_count; i++) {
+ const Vector3 &vert = vertices[i];
+ polygon_2d_vertices.write[i] = Vector2(vert.x, vert.z);
+ }
+ Vector<int> triangulated_polygon_2d_indices = Geometry2D::triangulate_polygon(polygon_2d_vertices);
+
+ NavigationServer3D *ns3d = NavigationServer3D::get_singleton();
+
+ if (triangulated_polygon_2d_indices.is_empty()) {
+ p_gizmo->add_lines(lines_mesh_vertices, ns3d->get_debug_navigation_avoidance_static_obstacle_pushin_edge_material());
+ } else {
+ p_gizmo->add_lines(lines_mesh_vertices, ns3d->get_debug_navigation_avoidance_static_obstacle_pushout_edge_material());
+ }
+ p_gizmo->add_collision_segments(lines_mesh_vertices);
+
+ if (p_gizmo->is_selected()) {
+ NavigationObstacle3DEditorPlugin::singleton->redraw();
+ }
+}
+
+bool NavigationObstacle3DGizmoPlugin::can_be_hidden() const {
+ return true;
+}
+
+int NavigationObstacle3DGizmoPlugin::get_priority() const {
+ return -1;
+}
+
+int NavigationObstacle3DGizmoPlugin::subgizmos_intersect_ray(const EditorNode3DGizmo *p_gizmo, Camera3D *p_camera, const Vector2 &p_point) const {
+ if (NavigationObstacle3DEditorPlugin::singleton->get_mode() != 1) { // MODE_EDIT
+ return -1;
+ }
+
+ NavigationObstacle3D *obstacle_node = Object::cast_to<NavigationObstacle3D>(p_gizmo->get_node_3d());
+ ERR_FAIL_NULL_V(obstacle_node, -1);
+
+ const Vector3 safe_scale = obstacle_node->get_global_basis().get_scale().abs().maxf(0.001);
+ const Transform3D gt = Transform3D(Basis().scaled(safe_scale).rotated(Vector3(0.0, 1.0, 0.0), obstacle_node->get_global_rotation().y), obstacle_node->get_global_position());
+ const Vector<Vector3> &vertices = obstacle_node->get_vertices();
+
+ for (int idx = 0; idx < vertices.size(); ++idx) {
+ Vector3 pos = gt.xform(vertices[idx]);
+ if (p_camera->unproject_position(pos).distance_to(p_point) < 20) {
+ return idx;
+ }
+ }
+
+ return -1;
+}
+
+Vector<int> NavigationObstacle3DGizmoPlugin::subgizmos_intersect_frustum(const EditorNode3DGizmo *p_gizmo, const Camera3D *p_camera, const Vector<Plane> &p_frustum) const {
+ Vector<int> contained_points;
+ if (NavigationObstacle3DEditorPlugin::singleton->get_mode() != 1) { // MODE_EDIT
+ return contained_points;
+ }
+
+ NavigationObstacle3D *obstacle_node = Object::cast_to<NavigationObstacle3D>(p_gizmo->get_node_3d());
+ ERR_FAIL_NULL_V(obstacle_node, contained_points);
+
+ const Vector3 safe_scale = obstacle_node->get_global_basis().get_scale().abs().maxf(0.001);
+ const Transform3D gt = Transform3D(Basis().scaled(safe_scale).rotated(Vector3(0.0, 1.0, 0.0), obstacle_node->get_global_rotation().y), obstacle_node->get_global_position());
+ const Vector<Vector3> &vertices = obstacle_node->get_vertices();
+
+ for (int idx = 0; idx < vertices.size(); ++idx) {
+ Vector3 pos = gt.xform(vertices[idx]);
+ bool is_contained_in_frustum = true;
+ for (int i = 0; i < p_frustum.size(); ++i) {
+ if (p_frustum[i].distance_to(pos) > 0) {
+ is_contained_in_frustum = false;
+ break;
+ }
+ }
+
+ if (is_contained_in_frustum) {
+ contained_points.push_back(idx);
+ }
+ }
+
+ return contained_points;
+}
+
+Transform3D NavigationObstacle3DGizmoPlugin::get_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id) const {
+ NavigationObstacle3D *obstacle_node = Object::cast_to<NavigationObstacle3D>(p_gizmo->get_node_3d());
+ ERR_FAIL_NULL_V(obstacle_node, Transform3D());
+
+ const Vector<Vector3> &vertices = obstacle_node->get_vertices();
+ ERR_FAIL_INDEX_V(p_id, vertices.size(), Transform3D());
+
+ const Basis safe_basis_inverse = Basis(Vector3(0.0, 1.0, 0.0), obstacle_node->get_global_rotation().y, obstacle_node->get_global_basis().get_scale().abs().maxf(0.001)).inverse();
+ Transform3D subgizmo_transform = Transform3D(Basis(), safe_basis_inverse.xform(vertices[p_id]));
+ return subgizmo_transform;
+}
+
+void NavigationObstacle3DGizmoPlugin::set_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id, Transform3D p_transform) {
+ NavigationObstacle3D *obstacle_node = Object::cast_to<NavigationObstacle3D>(p_gizmo->get_node_3d());
+ ERR_FAIL_NULL(obstacle_node);
+
+ const Basis safe_basis = Basis(Vector3(0.0, 1.0, 0.0), obstacle_node->get_global_rotation().y, obstacle_node->get_global_basis().get_scale().abs().maxf(0.001));
+ Vector3 new_vertex_pos = p_transform.origin;
+
+ Vector<Vector3> vertices = obstacle_node->get_vertices();
+ ERR_FAIL_INDEX(p_id, vertices.size());
+
+ Vector3 vertex = safe_basis.xform(new_vertex_pos);
+ vertex.y = 0.0;
+ vertices.write[p_id] = vertex;
-void NavigationObstacle3DEditor::_notification(int p_what) {
+ obstacle_node->set_vertices(vertices);
+}
+
+void NavigationObstacle3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel) {
+ NavigationObstacle3D *obstacle_node = Object::cast_to<NavigationObstacle3D>(p_gizmo->get_node_3d());
+ ERR_FAIL_NULL(obstacle_node);
+
+ const Basis safe_basis = Basis(Vector3(0.0, 1.0, 0.0), obstacle_node->get_global_rotation().y, obstacle_node->get_global_basis().get_scale().abs().maxf(0.001));
+
+ Vector<Vector3> vertices = obstacle_node->get_vertices();
+ Vector<Vector3> restore_vertices = vertices;
+
+ for (int i = 0; i < p_ids.size(); ++i) {
+ const int idx = p_ids[i];
+ Vector3 vertex = safe_basis.xform(p_restore[i].origin);
+ vertex.y = 0.0;
+ restore_vertices.write[idx] = vertex;
+ }
+
+ if (p_cancel) {
+ obstacle_node->set_vertices(restore_vertices);
+ return;
+ }
+
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->create_action(TTR("Set Obstacle Vertices"));
+ undo_redo->add_do_method(obstacle_node, "set_vertices", vertices);
+ undo_redo->add_undo_method(obstacle_node, "set_vertices", restore_vertices);
+ undo_redo->commit_action();
+}
+
+NavigationObstacle3DGizmoPlugin::NavigationObstacle3DGizmoPlugin() {
+ current_state = VISIBLE;
+}
+
+void NavigationObstacle3DEditorPlugin::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ _update_theme();
+ } break;
+
case NOTIFICATION_READY: {
- button_create->set_button_icon(get_editor_theme_icon(SNAME("Edit")));
- button_edit->set_button_icon(get_editor_theme_icon(SNAME("MovePoint")));
+ _update_theme();
button_edit->set_pressed(true);
- get_tree()->connect("node_removed", callable_mp(this, &NavigationObstacle3DEditor::_node_removed));
+ get_tree()->connect("node_removed", callable_mp(this, &NavigationObstacle3DEditorPlugin::_node_removed));
+ EditorNode::get_singleton()->get_gui_base()->connect(SceneStringName(theme_changed), callable_mp(this, &NavigationObstacle3DEditorPlugin::_update_theme));
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ get_tree()->disconnect("node_removed", callable_mp(this, &NavigationObstacle3DEditorPlugin::_node_removed));
+ EditorNode::get_singleton()->get_gui_base()->disconnect(SceneStringName(theme_changed), callable_mp(this, &NavigationObstacle3DEditorPlugin::_update_theme));
} break;
}
}
-void NavigationObstacle3DEditor::_node_removed(Node *p_node) {
- if (p_node == obstacle_node) {
- obstacle_node = nullptr;
- if (point_lines_meshinstance->get_parent() == p_node) {
- p_node->remove_child(point_lines_meshinstance);
+void NavigationObstacle3DEditorPlugin::edit(Object *p_object) {
+ obstacle_node = Object::cast_to<NavigationObstacle3D>(p_object);
+
+ RenderingServer *rs = RenderingServer::get_singleton();
+
+ if (obstacle_node) {
+ if (obstacle_node->get_vertices().is_empty()) {
+ set_mode(MODE_CREATE);
+ } else {
+ set_mode(MODE_EDIT);
}
- hide();
+ wip_vertices.clear();
+ wip_active = false;
+ edited_point = -1;
+
+ rs->instance_set_scenario(point_lines_instance_rid, obstacle_node->get_world_3d()->get_scenario());
+ rs->instance_set_scenario(point_handles_instance_rid, obstacle_node->get_world_3d()->get_scenario());
+
+ redraw();
+
+ } else {
+ obstacle_node = nullptr;
+
+ rs->mesh_clear(point_lines_mesh_rid);
+ rs->mesh_clear(point_handle_mesh_rid);
+ rs->instance_set_scenario(point_lines_instance_rid, RID());
+ rs->instance_set_scenario(point_handles_instance_rid, RID());
}
}
-void NavigationObstacle3DEditor::_menu_option(int p_option) {
- switch (p_option) {
- case MODE_CREATE: {
- mode = MODE_CREATE;
- button_create->set_pressed(true);
- button_edit->set_pressed(false);
- } break;
- case MODE_EDIT: {
- mode = MODE_EDIT;
- button_create->set_pressed(false);
- button_edit->set_pressed(true);
- } break;
+bool NavigationObstacle3DEditorPlugin::handles(Object *p_object) const {
+ return Object::cast_to<NavigationObstacle3D>(p_object);
+}
+
+void NavigationObstacle3DEditorPlugin::make_visible(bool p_visible) {
+ if (p_visible) {
+ obstacle_editor->show();
+ } else {
+ obstacle_editor->hide();
+ edit(nullptr);
}
}
-void NavigationObstacle3DEditor::_wip_close() {
- ERR_FAIL_NULL_MSG(obstacle_node, "Edited NavigationObstacle3D is not valid.");
+void NavigationObstacle3DEditorPlugin::action_flip_vertices() {
+ if (!obstacle_node) {
+ return;
+ }
+
+ Vector<Vector3> flipped_vertices = obstacle_node->get_vertices();
+ flipped_vertices.reverse();
+
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Set NavigationObstacle3D Vertices"));
+ undo_redo->create_action(TTR("Edit Obstacle (Flip Winding)"));
+ undo_redo->add_do_method(obstacle_node, "set_vertices", flipped_vertices);
undo_redo->add_undo_method(obstacle_node, "set_vertices", obstacle_node->get_vertices());
+ undo_redo->commit_action();
- PackedVector3Array polygon_3d_vertices;
- Vector<int> triangulated_polygon_2d_indices = Geometry2D::triangulate_polygon(wip);
+ obstacle_node->update_gizmos();
+}
- if (!triangulated_polygon_2d_indices.is_empty()) {
- polygon_3d_vertices.resize(wip.size());
- Vector3 *polygon_3d_vertices_ptr = polygon_3d_vertices.ptrw();
- for (int i = 0; i < wip.size(); i++) {
- const Vector2 &vert = wip[i];
- polygon_3d_vertices_ptr[i] = Vector3(vert.x, 0.0, vert.y);
- }
+void NavigationObstacle3DEditorPlugin::action_clear_vertices() {
+ if (!obstacle_node) {
+ return;
}
- undo_redo->add_do_method(obstacle_node, "set_vertices", polygon_3d_vertices);
- undo_redo->add_do_method(this, "_polygon_draw");
- undo_redo->add_undo_method(this, "_polygon_draw");
- wip.clear();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->create_action(TTR("Edit Obstacle (Clear Vertices)"));
+ undo_redo->add_do_method(obstacle_node, "set_vertices", Vector<Vector3>());
+ undo_redo->add_undo_method(obstacle_node, "set_vertices", obstacle_node->get_vertices());
+ undo_redo->commit_action();
+
+ obstacle_node->update_gizmos();
+ edit(obstacle_node);
+}
+
+void NavigationObstacle3DEditorPlugin::_update_theme() {
+ button_create->set_tooltip_text(TTR("Add Vertex"));
+ button_edit->set_tooltip_text(TTR("Edit Vertex"));
+ button_delete->set_tooltip_text(TTR("Delete Vertex"));
+ button_flip->set_tooltip_text(TTR("Flip Winding"));
+ button_clear->set_tooltip_text(TTR("Clear Vertices"));
+ button_create->set_button_icon(button_create->get_editor_theme_icon(SNAME("CurveCreate")));
+ button_edit->set_button_icon(button_edit->get_editor_theme_icon(SNAME("CurveEdit")));
+ button_delete->set_button_icon(button_delete->get_editor_theme_icon(SNAME("CurveDelete")));
+ button_flip->set_button_icon(button_flip->get_editor_theme_icon(SNAME("FlipWinding")));
+ button_clear->set_button_icon(button_clear->get_editor_theme_icon(SNAME("Clear")));
+}
+
+void NavigationObstacle3DEditorPlugin::_node_removed(Node *p_node) {
+ if (obstacle_node == p_node) {
+ obstacle_node = nullptr;
+
+ RenderingServer *rs = RenderingServer::get_singleton();
+ rs->mesh_clear(point_lines_mesh_rid);
+ rs->mesh_clear(point_handle_mesh_rid);
+
+ obstacle_editor->hide();
+ }
+}
+
+void NavigationObstacle3DEditorPlugin::set_mode(int p_option) {
+ if (p_option == NavigationObstacle3DEditorPlugin::ACTION_FLIP) {
+ button_flip->set_pressed(false);
+ action_flip_vertices();
+ return;
+ }
+
+ if (p_option == NavigationObstacle3DEditorPlugin::ACTION_CLEAR) {
+ button_clear->set_pressed(false);
+ button_clear_dialog->reset_size();
+ button_clear_dialog->popup_centered();
+ return;
+ }
+
+ mode = p_option;
+
+ button_create->set_pressed(p_option == NavigationObstacle3DEditorPlugin::MODE_CREATE);
+ button_edit->set_pressed(p_option == NavigationObstacle3DEditorPlugin::MODE_EDIT);
+ button_delete->set_pressed(p_option == NavigationObstacle3DEditorPlugin::MODE_DELETE);
+ button_flip->set_pressed(false);
+ button_clear->set_pressed(false);
+}
+
+void NavigationObstacle3DEditorPlugin::_wip_cancel() {
+ wip_vertices.clear();
wip_active = false;
- mode = MODE_EDIT;
- button_edit->set_pressed(true);
- button_create->set_pressed(false);
+
edited_point = -1;
- undo_redo->commit_action();
+
+ redraw();
+}
+
+void NavigationObstacle3DEditorPlugin::_wip_close() {
+ ERR_FAIL_NULL_MSG(obstacle_node, "Edited NavigationObstacle3D is not valid.");
+
+ Vector<Vector2> wip_2d_vertices;
+ wip_2d_vertices.resize(wip_vertices.size());
+ for (int i = 0; i < wip_vertices.size(); i++) {
+ const Vector3 &vert = wip_vertices[i];
+ wip_2d_vertices.write[i] = Vector2(vert.x, vert.z);
+ }
+ Vector<int> triangulated_polygon_2d_indices = Geometry2D::triangulate_polygon(wip_2d_vertices);
+
+ if (!triangulated_polygon_2d_indices.is_empty()) {
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->create_action(TTR("Set Obstacle Vertices"));
+ undo_redo->add_do_method(obstacle_node, "set_vertices", wip_vertices);
+ undo_redo->add_undo_method(obstacle_node, "set_vertices", obstacle_node->get_vertices());
+ undo_redo->commit_action();
+
+ wip_vertices.clear();
+ wip_active = false;
+ //mode = MODE_EDIT;
+ NavigationObstacle3DEditorPlugin::singleton->set_mode(NavigationObstacle3DEditorPlugin::MODE_EDIT);
+ button_edit->set_pressed(true);
+ button_create->set_pressed(false);
+ edited_point = -1;
+ }
}
-EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
+EditorPlugin::AfterGUIInput NavigationObstacle3DEditorPlugin::forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
if (!obstacle_node) {
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
- // Use special transformation rules for NavigationObstacle3D: Only take global y-rotation into account and limit scaling to positive values.
- Transform3D gt;
- gt.origin = obstacle_node->get_global_position();
- gt.scale_basis(obstacle_node->get_global_basis().get_scale().abs().maxf(0.001));
- gt.rotate_basis(Vector3(0.0, 1.0, 0.0), obstacle_node->get_global_rotation().y);
- Transform3D gi = gt.affine_inverse();
- Plane p(Vector3(0.0, 1.0, 0.0), gt.origin);
- point_lines_meshinstance->set_transform(gt.translated(Vector3(0.0, 0.0, 0.00001)));
+ if (!obstacle_node->is_visible_in_tree()) {
+ return EditorPlugin::AFTER_GUI_INPUT_PASS;
+ }
+
+ Ref<InputEventMouse> mouse_event = p_event;
+
+ if (mouse_event.is_null()) {
+ return EditorPlugin::AFTER_GUI_INPUT_PASS;
+ }
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- Vector2 gpoint = mb->get_position();
- Vector3 ray_from = p_camera->project_ray_origin(gpoint);
- Vector3 ray_dir = p_camera->project_ray_normal(gpoint);
+ Vector2 mouse_position = mb->get_position();
+ Vector3 ray_from = p_camera->project_ray_origin(mouse_position);
+ Vector3 ray_dir = p_camera->project_ray_normal(mouse_position);
+
+ const Vector3 safe_scale = obstacle_node->get_global_basis().get_scale().abs().maxf(0.001);
+ const Transform3D gt = Transform3D(Basis().scaled(safe_scale).rotated(Vector3(0.0, 1.0, 0.0), obstacle_node->get_global_rotation().y), obstacle_node->get_global_position());
+ Transform3D gi = gt.affine_inverse();
+ Plane projection_plane(Vector3(0.0, 1.0, 0.0), gt.origin);
Vector3 spoint;
- if (!p.intersects_ray(ray_from, ray_dir, &spoint)) {
+ if (!projection_plane.intersects_ray(ray_from, ray_dir, &spoint)) {
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
spoint = gi.xform(spoint);
- Vector2 cpoint(spoint.x, spoint.z);
-
- //DO NOT snap here, it's confusing in 3D for adding points.
- //Let the snap happen when the point is being moved, instead.
- //cpoint = CanvasItemEditor::get_singleton()->snap_point(cpoint);
-
- PackedVector2Array poly = _get_polygon();
+ Vector3 cpoint = Vector3(spoint.x, 0.0, spoint.z);
+ Vector<Vector3> obstacle_vertices = obstacle_node->get_vertices();
- //first check if a point is to be added (segment split)
real_t grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius");
switch (mode) {
case MODE_CREATE: {
if (mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
+ if (obstacle_vertices.size() >= 3) {
+ int closest_idx = -1;
+ Vector2 closest_edge_point;
+ real_t closest_dist = 1e10;
+ for (int i = 0; i < obstacle_vertices.size(); i++) {
+ Vector2 points[2] = {
+ p_camera->unproject_position(gt.xform(obstacle_vertices[i])),
+ p_camera->unproject_position(gt.xform(obstacle_vertices[(i + 1) % obstacle_vertices.size()]))
+ };
+
+ Vector2 cp = Geometry2D::get_closest_point_to_segment(mouse_position, points);
+ if (cp.distance_squared_to(points[0]) < grab_threshold || cp.distance_squared_to(points[1]) < grab_threshold) {
+ continue; // Skip edge as clicked point is too close to existing vertex.
+ }
+
+ real_t d = cp.distance_to(mouse_position);
+ if (d < closest_dist && d < grab_threshold) {
+ closest_dist = d;
+ closest_edge_point = cp;
+ closest_idx = i;
+ }
+ }
+ if (closest_idx >= 0) {
+ edited_point = -1;
+ Vector3 _ray_from = p_camera->project_ray_origin(closest_edge_point);
+ Vector3 _ray_dir = p_camera->project_ray_normal(closest_edge_point);
+ Vector3 edge_intersection_point;
+ if (projection_plane.intersects_ray(_ray_from, _ray_dir, &edge_intersection_point)) {
+ edge_intersection_point = gi.xform(edge_intersection_point);
+
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->create_action(TTR("Edit Obstacle (Add Vertex)"));
+ undo_redo->add_undo_method(obstacle_node, "set_vertices", obstacle_vertices);
+ obstacle_vertices.insert(closest_idx + 1, edge_intersection_point);
+ undo_redo->add_do_method(obstacle_node, "set_vertices", obstacle_vertices);
+ undo_redo->commit_action();
+ redraw();
+ return EditorPlugin::AFTER_GUI_INPUT_STOP;
+ }
+ }
+ }
if (!wip_active) {
- wip.clear();
- wip.push_back(cpoint);
+ wip_vertices.clear();
+ wip_vertices.push_back(cpoint);
wip_active = true;
edited_point_pos = cpoint;
snap_ignore = false;
- _polygon_draw();
+ redraw();
edited_point = 1;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else {
- if (wip.size() > 1 && p_camera->unproject_position(gt.xform(Vector3(wip[0].x, 0.0, wip[0].y))).distance_to(gpoint) < grab_threshold) {
- //wip closed
+ if (wip_vertices.size() > 1 && p_camera->unproject_position(gt.xform(wip_vertices[0])).distance_to(mouse_position) < grab_threshold) {
_wip_close();
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else {
- wip.push_back(cpoint);
- edited_point = wip.size();
+ wip_vertices.push_back(cpoint);
+ edited_point = wip_vertices.size();
snap_ignore = false;
- _polygon_draw();
+ redraw();
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
@@ -186,13 +543,11 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Cam
if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
if (mb->is_ctrl_pressed()) {
- if (poly.size() < 3) {
+ if (obstacle_vertices.size() < 3) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Edit Vertices"));
+ undo_redo->create_action(TTR("Edit Obstacle (Add Vertex)"));
undo_redo->add_undo_method(obstacle_node, "set_vertices", obstacle_node->get_vertices());
- poly.push_back(cpoint);
- undo_redo->add_do_method(this, "_polygon_draw");
- undo_redo->add_undo_method(this, "_polygon_draw");
+ obstacle_vertices.push_back(cpoint);
undo_redo->commit_action();
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
@@ -201,18 +556,18 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Cam
int closest_idx = -1;
Vector2 closest_pos;
real_t closest_dist = 1e10;
- for (int i = 0; i < poly.size(); i++) {
+ for (int i = 0; i < obstacle_vertices.size(); i++) {
Vector2 points[2] = {
- p_camera->unproject_position(gt.xform(Vector3(poly[i].x, 0.0, poly[i].y))),
- p_camera->unproject_position(gt.xform(Vector3(poly[(i + 1) % poly.size()].x, 0.0, poly[(i + 1) % poly.size()].y)))
+ p_camera->unproject_position(gt.xform(obstacle_vertices[i])),
+ p_camera->unproject_position(gt.xform(obstacle_vertices[(i + 1) % obstacle_vertices.size()]))
};
- Vector2 cp = Geometry2D::get_closest_point_to_segment(gpoint, points);
+ Vector2 cp = Geometry2D::get_closest_point_to_segment(mouse_position, points);
if (cp.distance_squared_to(points[0]) < CMP_EPSILON2 || cp.distance_squared_to(points[1]) < CMP_EPSILON2) {
continue; //not valid to reuse point
}
- real_t d = cp.distance_to(gpoint);
+ real_t d = cp.distance_to(mouse_position);
if (d < closest_dist && d < grab_threshold) {
closest_dist = d;
closest_pos = cp;
@@ -221,26 +576,24 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Cam
}
if (closest_idx >= 0) {
- pre_move_edit = poly;
- poly.insert(closest_idx + 1, cpoint);
+ pre_move_edit = obstacle_vertices;
+ obstacle_vertices.insert(closest_idx + 1, cpoint);
edited_point = closest_idx + 1;
edited_point_pos = cpoint;
- _set_polygon(poly);
- _polygon_draw();
+ obstacle_node->set_vertices(obstacle_vertices);
+ redraw();
snap_ignore = true;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
} else {
- //look for points to move
-
int closest_idx = -1;
Vector2 closest_pos;
real_t closest_dist = 1e10;
- for (int i = 0; i < poly.size(); i++) {
- Vector2 cp = p_camera->unproject_position(gt.xform(Vector3(poly[i].x, 0.0, poly[i].y)));
+ for (int i = 0; i < obstacle_vertices.size(); i++) {
+ Vector2 cp = p_camera->unproject_position(gt.xform(obstacle_vertices[i]));
- real_t d = cp.distance_to(gpoint);
+ real_t d = cp.distance_to(mouse_position);
if (d < closest_dist && d < grab_threshold) {
closest_dist = d;
closest_pos = cp;
@@ -249,10 +602,10 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Cam
}
if (closest_idx >= 0) {
- pre_move_edit = poly;
+ pre_move_edit = obstacle_vertices;
edited_point = closest_idx;
- edited_point_pos = poly[closest_idx];
- _polygon_draw();
+ edited_point_pos = obstacle_vertices[closest_idx];
+ redraw();
snap_ignore = false;
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
@@ -261,16 +614,13 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Cam
snap_ignore = false;
if (edited_point != -1) {
- //apply
+ ERR_FAIL_INDEX_V(edited_point, obstacle_vertices.size(), EditorPlugin::AFTER_GUI_INPUT_PASS);
+ obstacle_vertices.write[edited_point] = edited_point_pos;
- ERR_FAIL_INDEX_V(edited_point, poly.size(), EditorPlugin::AFTER_GUI_INPUT_PASS);
- poly.write[edited_point] = edited_point_pos;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Edit Poly"));
- //undo_redo->add_do_method(obj, "set_polygon", poly);
- //undo_redo->add_undo_method(obj, "set_polygon", pre_move_edit);
- undo_redo->add_do_method(this, "_polygon_draw");
- undo_redo->add_undo_method(this, "_polygon_draw");
+ undo_redo->create_action(TTR("Edit Obstacle (Move Vertex)"));
+ undo_redo->add_undo_method(obstacle_node, "set_vertices", obstacle_node->get_vertices());
+ undo_redo->add_do_method(obstacle_node, "set_vertices", obstacle_vertices);
undo_redo->commit_action();
edited_point = -1;
@@ -278,30 +628,31 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Cam
}
}
}
- if (mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed() && edited_point == -1) {
+
+ } break;
+
+ case MODE_DELETE: {
+ if (mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
int closest_idx = -1;
- Vector2 closest_pos;
real_t closest_dist = 1e10;
- for (int i = 0; i < poly.size(); i++) {
- Vector2 cp = p_camera->unproject_position(gt.xform(Vector3(poly[i].x, 0.0, poly[i].y)));
-
- real_t d = cp.distance_to(gpoint);
+ for (int i = 0; i < obstacle_vertices.size(); i++) {
+ Vector2 point = p_camera->unproject_position(gt.xform(obstacle_vertices[i]));
+ real_t d = point.distance_to(mouse_position);
if (d < closest_dist && d < grab_threshold) {
closest_dist = d;
- closest_pos = cp;
closest_idx = i;
}
}
if (closest_idx >= 0) {
+ edited_point = -1;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Edit Poly (Remove Point)"));
- //undo_redo->add_undo_method(obj, "set_polygon", poly);
- poly.remove_at(closest_idx);
- //undo_redo->add_do_method(obj, "set_polygon", poly);
- undo_redo->add_do_method(this, "_polygon_draw");
- undo_redo->add_undo_method(this, "_polygon_draw");
+ undo_redo->create_action(TTR("Edit Obstacle (Remove Vertex)"));
+ undo_redo->add_undo_method(obstacle_node, "set_vertices", obstacle_vertices);
+ obstacle_vertices.remove_at(closest_idx);
+ undo_redo->add_do_method(obstacle_node, "set_vertices", obstacle_vertices);
undo_redo->commit_action();
+ redraw();
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
@@ -314,20 +665,25 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Cam
if (mm.is_valid()) {
if (edited_point != -1 && (wip_active || mm->get_button_mask().has_flag(MouseButtonMask::LEFT))) {
- Vector2 gpoint = mm->get_position();
+ Vector2 mouse_position = mm->get_position();
- Vector3 ray_from = p_camera->project_ray_origin(gpoint);
- Vector3 ray_dir = p_camera->project_ray_normal(gpoint);
+ Vector3 ray_from = p_camera->project_ray_origin(mouse_position);
+ Vector3 ray_dir = p_camera->project_ray_normal(mouse_position);
- Vector3 spoint;
+ const Vector3 safe_scale = obstacle_node->get_global_basis().get_scale().abs().maxf(0.001);
+ const Transform3D gt = Transform3D(Basis().scaled(safe_scale).rotated(Vector3(0.0, 1.0, 0.0), obstacle_node->get_global_rotation().y), obstacle_node->get_global_position());
+ Transform3D gi = gt.affine_inverse();
+ Plane projection_plane(Vector3(0.0, 1.0, 0.0), gt.origin);
- if (!p.intersects_ray(ray_from, ray_dir, &spoint)) {
+ Vector3 intersection_point;
+
+ if (!projection_plane.intersects_ray(ray_from, ray_dir, &intersection_point)) {
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
- spoint = gi.xform(spoint);
+ intersection_point = gi.xform(intersection_point);
- Vector2 cpoint(spoint.x, spoint.z);
+ Vector2 cpoint(intersection_point.x, intersection_point.z);
if (snap_ignore && !Input::get_singleton()->is_key_pressed(Key::CTRL)) {
snap_ignore = false;
@@ -336,220 +692,219 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Cam
if (!snap_ignore && Node3DEditor::get_singleton()->is_snap_enabled()) {
cpoint = cpoint.snappedf(Node3DEditor::get_singleton()->get_translate_snap());
}
- edited_point_pos = cpoint;
+ edited_point_pos = Vector3(cpoint.x, 0.0, cpoint.y);
- _polygon_draw();
+ redraw();
}
}
- return EditorPlugin::AFTER_GUI_INPUT_PASS;
-}
+ Ref<InputEventKey> k = p_event;
-PackedVector2Array NavigationObstacle3DEditor::_get_polygon() {
- ERR_FAIL_NULL_V_MSG(obstacle_node, PackedVector2Array(), "Edited object is not valid.");
- return PackedVector2Array(obstacle_node->call("get_polygon"));
-}
+ if (k.is_valid() && k->is_pressed()) {
+ if (wip_active && k->get_keycode() == Key::ENTER) {
+ _wip_close();
+ } else if (wip_active && k->get_keycode() == Key::ESCAPE) {
+ _wip_cancel();
+ }
+ }
-void NavigationObstacle3DEditor::_set_polygon(const PackedVector2Array &p_poly) {
- ERR_FAIL_NULL_MSG(obstacle_node, "Edited object is not valid.");
- obstacle_node->call("set_polygon", p_poly);
+ return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
-void NavigationObstacle3DEditor::_polygon_draw() {
+void NavigationObstacle3DEditorPlugin::redraw() {
if (!obstacle_node) {
return;
}
+ RenderingServer *rs = RenderingServer::get_singleton();
+
+ rs->mesh_clear(point_lines_mesh_rid);
+ rs->mesh_clear(point_handle_mesh_rid);
+
+ if (!obstacle_node->is_visible_in_tree()) {
+ return;
+ }
- PackedVector2Array poly;
- PackedVector3Array polygon_3d_vertices;
+ Vector<Vector3> edited_vertices;
if (wip_active) {
- poly = wip;
+ edited_vertices = wip_vertices;
} else {
- poly = _get_polygon();
+ edited_vertices = obstacle_node->get_vertices();
}
- polygon_3d_vertices.resize(poly.size());
- Vector3 *polygon_3d_vertices_ptr = polygon_3d_vertices.ptrw();
- for (int i = 0; i < poly.size(); i++) {
- const Vector2 &vert = poly[i];
- polygon_3d_vertices_ptr[i] = Vector3(vert.x, 0.0, vert.y);
+ if (edited_vertices.is_empty()) {
+ return;
}
- point_handle_mesh->clear_surfaces();
- point_lines_mesh->clear_surfaces();
- point_lines_meshinstance->set_material_override(line_material);
+ Array point_lines_mesh_array;
+ point_lines_mesh_array.resize(Mesh::ARRAY_MAX);
- if (poly.is_empty()) {
- return;
- }
+ Vector<Vector3> point_lines_mesh_vertices;
+ point_lines_mesh_vertices.resize(edited_vertices.size() * 2);
+ Vector3 *point_lines_mesh_vertices_ptr = point_lines_mesh_vertices.ptrw();
- point_lines_mesh->surface_begin(Mesh::PRIMITIVE_LINES);
+ int vertex_index = 0;
- for (int i = 0; i < poly.size(); i++) {
- Vector2 p, p2;
+ for (int i = 0; i < edited_vertices.size(); i++) {
+ Vector3 point, next_point;
if (i == edited_point) {
- p = edited_point_pos;
+ point = edited_point_pos;
} else {
- p = poly[i];
+ point = edited_vertices[i];
}
- if ((wip_active && i == poly.size() - 1) || (((i + 1) % poly.size()) == edited_point)) {
- p2 = edited_point_pos;
+ if ((wip_active && i == edited_vertices.size() - 1) || (((i + 1) % edited_vertices.size()) == edited_point)) {
+ next_point = edited_point_pos;
} else {
- p2 = poly[(i + 1) % poly.size()];
+ next_point = edited_vertices[(i + 1) % edited_vertices.size()];
}
- Vector3 point = Vector3(p.x, 0.0, p.y);
- Vector3 next_point = Vector3(p2.x, 0.0, p2.y);
-
- point_lines_mesh->surface_set_color(Color(1, 0.3, 0.1, 0.8));
- point_lines_mesh->surface_add_vertex(point);
- point_lines_mesh->surface_set_color(Color(1, 0.3, 0.1, 0.8));
- point_lines_mesh->surface_add_vertex(next_point);
-
- //Color col=Color(1,0.3,0.1,0.8);
- //vpc->draw_line(point,next_point,col,2);
- //vpc->draw_texture(handle,point-handle->get_size()*0.5);
+ point_lines_mesh_vertices_ptr[vertex_index++] = point;
+ point_lines_mesh_vertices_ptr[vertex_index++] = next_point;
}
- point_lines_mesh->surface_end();
+ point_lines_mesh_array[Mesh::ARRAY_VERTEX] = point_lines_mesh_vertices;
+
+ rs->mesh_add_surface_from_arrays(point_lines_mesh_rid, RS::PRIMITIVE_LINES, point_lines_mesh_array);
+ rs->instance_set_surface_override_material(point_lines_instance_rid, 0, line_material->get_rid());
+ const Vector3 safe_scale = obstacle_node->get_global_basis().get_scale().abs().maxf(0.001);
+ const Transform3D gt = Transform3D(Basis().scaled(safe_scale).rotated(Vector3(0.0, 1.0, 0.0), obstacle_node->get_global_rotation().y), obstacle_node->get_global_position());
+ rs->instance_set_transform(point_lines_instance_rid, gt);
Array point_handle_mesh_array;
point_handle_mesh_array.resize(Mesh::ARRAY_MAX);
Vector<Vector3> point_handle_mesh_vertices;
- point_handle_mesh_vertices.resize(poly.size());
+ point_handle_mesh_vertices.resize(edited_vertices.size());
Vector3 *point_handle_mesh_vertices_ptr = point_handle_mesh_vertices.ptrw();
- for (int i = 0; i < poly.size(); i++) {
- Vector2 point_2d;
- Vector2 p2;
+ for (int i = 0; i < edited_vertices.size(); i++) {
+ Vector3 point_handle_3d;
if (i == edited_point) {
- point_2d = edited_point_pos;
+ point_handle_3d = edited_point_pos;
} else {
- point_2d = poly[i];
+ point_handle_3d = edited_vertices[i];
}
- Vector3 point_handle_3d = Vector3(point_2d.x, 0.0, point_2d.y);
point_handle_mesh_vertices_ptr[i] = point_handle_3d;
}
point_handle_mesh_array[Mesh::ARRAY_VERTEX] = point_handle_mesh_vertices;
- point_handle_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_POINTS, point_handle_mesh_array);
- point_handle_mesh->surface_set_material(0, handle_material);
-}
-
-void NavigationObstacle3DEditor::edit(Node *p_node) {
- obstacle_node = Object::cast_to<NavigationObstacle3D>(p_node);
- if (obstacle_node) {
- //Enable the pencil tool if the polygon is empty
- if (_get_polygon().is_empty()) {
- _menu_option(MODE_CREATE);
- }
- wip.clear();
- wip_active = false;
- edited_point = -1;
- if (point_lines_meshinstance->get_parent()) {
- point_lines_meshinstance->reparent(p_node, false);
- } else {
- p_node->add_child(point_lines_meshinstance);
- }
- _polygon_draw();
-
- } else {
- obstacle_node = nullptr;
-
- if (point_lines_meshinstance->get_parent()) {
- point_lines_meshinstance->get_parent()->remove_child(point_lines_meshinstance);
- }
- }
+ rs->mesh_add_surface_from_arrays(point_handle_mesh_rid, RS::PRIMITIVE_POINTS, point_handle_mesh_array);
+ rs->instance_set_surface_override_material(point_handles_instance_rid, 0, handle_material->get_rid());
+ rs->instance_set_transform(point_handles_instance_rid, gt);
}
-void NavigationObstacle3DEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_polygon_draw"), &NavigationObstacle3DEditor::_polygon_draw);
-}
-
-NavigationObstacle3DEditor::NavigationObstacle3DEditor() {
- obstacle_node = nullptr;
-
- button_create = memnew(Button);
- button_create->set_theme_type_variation("FlatButton");
- add_child(button_create);
- button_create->connect(SceneStringName(pressed), callable_mp(this, &NavigationObstacle3DEditor::_menu_option).bind(MODE_CREATE));
- button_create->set_toggle_mode(true);
-
- button_edit = memnew(Button);
- button_edit->set_theme_type_variation("FlatButton");
- add_child(button_edit);
- button_edit->connect(SceneStringName(pressed), callable_mp(this, &NavigationObstacle3DEditor::_menu_option).bind(MODE_EDIT));
- button_edit->set_toggle_mode(true);
+NavigationObstacle3DEditorPlugin *NavigationObstacle3DEditorPlugin::singleton = nullptr;
- mode = MODE_EDIT;
- wip_active = false;
- point_lines_meshinstance = memnew(MeshInstance3D);
- point_lines_mesh.instantiate();
- point_lines_meshinstance->set_mesh(point_lines_mesh);
- point_lines_meshinstance->set_transform(Transform3D(Basis(), Vector3(0, 0, 0.00001)));
- point_lines_meshinstance->set_as_top_level(true);
+NavigationObstacle3DEditorPlugin::NavigationObstacle3DEditorPlugin() {
+ singleton = this;
- line_material.instantiate();
+ line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- line_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
line_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
line_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
line_material->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
- line_material->set_albedo(Color(1, 1, 1));
+ line_material->set_albedo(Color(1, 0.3, 0.1, 0.8));
+ line_material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
- handle_material.instantiate();
+ handle_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
handle_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- handle_material->set_flag(StandardMaterial3D::FLAG_USE_POINT_SIZE, true);
handle_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ handle_material->set_flag(StandardMaterial3D::FLAG_USE_POINT_SIZE, true);
handle_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
handle_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
handle_material->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
Ref<Texture2D> handle = EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Editor3DHandle"), EditorStringName(EditorIcons));
handle_material->set_point_size(handle->get_width());
handle_material->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, handle);
+ handle_material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
- point_handles_meshinstance = memnew(MeshInstance3D);
- point_lines_meshinstance->add_child(point_handles_meshinstance);
- point_handle_mesh.instantiate();
- point_handles_meshinstance->set_mesh(point_handle_mesh);
- point_handles_meshinstance->set_transform(Transform3D(Basis(), Vector3(0, 0, 0.00001)));
+ RenderingServer *rs = RenderingServer::get_singleton();
- snap_ignore = false;
-}
+ point_lines_mesh_rid = rs->mesh_create();
+ point_handle_mesh_rid = rs->mesh_create();
-NavigationObstacle3DEditor::~NavigationObstacle3DEditor() {
- memdelete(point_lines_meshinstance);
-}
+ point_lines_instance_rid = rs->instance_create();
+ point_handles_instance_rid = rs->instance_create();
-void NavigationObstacle3DEditorPlugin::edit(Object *p_object) {
- obstacle_editor->edit(Object::cast_to<Node>(p_object));
-}
+ rs->instance_set_base(point_lines_instance_rid, point_lines_mesh_rid);
+ rs->instance_set_base(point_handles_instance_rid, point_handle_mesh_rid);
-bool NavigationObstacle3DEditorPlugin::handles(Object *p_object) const {
- return Object::cast_to<NavigationObstacle3D>(p_object);
-}
+ obstacle_editor = memnew(HBoxContainer);
+ obstacle_editor->hide();
-void NavigationObstacle3DEditorPlugin::make_visible(bool p_visible) {
- if (p_visible) {
- obstacle_editor->show();
- } else {
- obstacle_editor->hide();
- obstacle_editor->edit(nullptr);
- }
-}
+ Ref<ButtonGroup> bg;
+ bg.instantiate();
+
+ button_create = memnew(Button);
+ button_create->set_theme_type_variation("FlatButton");
+ obstacle_editor->add_child(button_create);
+ button_create->set_tooltip_text(TTR("Add Vertex"));
+ button_create->connect(SceneStringName(pressed), callable_mp(this, &NavigationObstacle3DEditorPlugin::set_mode).bind(NavigationObstacle3DEditorPlugin::MODE_CREATE));
+ button_create->set_toggle_mode(true);
+ button_create->set_button_group(bg);
+
+ button_edit = memnew(Button);
+ button_edit->set_theme_type_variation("FlatButton");
+ obstacle_editor->add_child(button_edit);
+ button_edit->connect(SceneStringName(pressed), callable_mp(this, &NavigationObstacle3DEditorPlugin::set_mode).bind(NavigationObstacle3DEditorPlugin::MODE_EDIT));
+ button_edit->set_toggle_mode(true);
+ button_edit->set_button_group(bg);
+
+ button_delete = memnew(Button);
+ button_delete->set_theme_type_variation("FlatButton");
+ obstacle_editor->add_child(button_delete);
+ button_delete->connect(SceneStringName(pressed), callable_mp(this, &NavigationObstacle3DEditorPlugin::set_mode).bind(NavigationObstacle3DEditorPlugin::MODE_DELETE));
+ button_delete->set_toggle_mode(true);
+ button_delete->set_button_group(bg);
+
+ button_flip = memnew(Button);
+ button_flip->set_theme_type_variation("FlatButton");
+ obstacle_editor->add_child(button_flip);
+ button_flip->connect(SceneStringName(pressed), callable_mp(this, &NavigationObstacle3DEditorPlugin::set_mode).bind(NavigationObstacle3DEditorPlugin::ACTION_FLIP));
+ button_flip->set_toggle_mode(true);
+
+ button_clear = memnew(Button);
+ button_clear->set_theme_type_variation("FlatButton");
+ obstacle_editor->add_child(button_clear);
+ button_clear->connect(SceneStringName(pressed), callable_mp(this, &NavigationObstacle3DEditorPlugin::set_mode).bind(NavigationObstacle3DEditorPlugin::ACTION_CLEAR));
+ button_clear->set_toggle_mode(true);
+
+ button_clear_dialog = memnew(ConfirmationDialog);
+ button_clear_dialog->set_title(TTR("Please Confirm..."));
+ button_clear_dialog->set_text(TTR("Remove all vertices?"));
+ button_clear_dialog->connect(SceneStringName(confirmed), callable_mp(NavigationObstacle3DEditorPlugin::singleton, &NavigationObstacle3DEditorPlugin::action_clear_vertices));
+ obstacle_editor->add_child(button_clear_dialog);
-NavigationObstacle3DEditorPlugin::NavigationObstacle3DEditorPlugin() {
- obstacle_editor = memnew(NavigationObstacle3DEditor);
Node3DEditor::get_singleton()->add_control_to_menu_panel(obstacle_editor);
- obstacle_editor->hide();
+ Ref<NavigationObstacle3DGizmoPlugin> gizmo_plugin = memnew(NavigationObstacle3DGizmoPlugin());
+ obstacle_3d_gizmo_plugin = gizmo_plugin;
+ Node3DEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin);
}
NavigationObstacle3DEditorPlugin::~NavigationObstacle3DEditorPlugin() {
+ RenderingServer *rs = RenderingServer::get_singleton();
+ ERR_FAIL_NULL(rs);
+
+ if (point_lines_instance_rid.is_valid()) {
+ rs->free(point_lines_instance_rid);
+ point_lines_instance_rid = RID();
+ }
+ if (point_lines_mesh_rid.is_valid()) {
+ rs->free(point_lines_mesh_rid);
+ point_lines_mesh_rid = RID();
+ }
+
+ if (point_handles_instance_rid.is_valid()) {
+ rs->free(point_handles_instance_rid);
+ point_handles_instance_rid = RID();
+ }
+ if (point_handle_mesh_rid.is_valid()) {
+ rs->free(point_handle_mesh_rid);
+ point_handle_mesh_rid = RID();
+ }
}
diff --git a/editor/plugins/navigation_obstacle_3d_editor_plugin.h b/editor/plugins/navigation_obstacle_3d_editor_plugin.h
index c62a5a281b..b6f3a11cf6 100644
--- a/editor/plugins/navigation_obstacle_3d_editor_plugin.h
+++ b/editor/plugins/navigation_obstacle_3d_editor_plugin.h
@@ -32,79 +32,99 @@
#define NAVIGATION_OBSTACLE_3D_EDITOR_PLUGIN_H
#include "editor/plugins/editor_plugin.h"
-#include "scene/3d/mesh_instance_3d.h"
-#include "scene/3d/physics/collision_polygon_3d.h"
+#include "editor/plugins/node_3d_editor_gizmos.h"
#include "scene/gui/box_container.h"
-#include "scene/resources/immediate_mesh.h"
-#include "scene/3d/navigation_obstacle_3d.h"
+class Button;
+class ConfirmationDialog;
+class NavigationObstacle3D;
-class CanvasItemEditor;
-class MenuButton;
+class NavigationObstacle3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+ GDCLASS(NavigationObstacle3DGizmoPlugin, EditorNode3DGizmoPlugin);
-class NavigationObstacle3DEditor : public HBoxContainer {
- GDCLASS(NavigationObstacle3DEditor, HBoxContainer);
+public:
+ virtual bool has_gizmo(Node3D *p_spatial) override;
+ virtual String get_gizmo_name() const override;
- enum Mode {
- MODE_CREATE,
- MODE_EDIT,
+ virtual void redraw(EditorNode3DGizmo *p_gizmo) override;
- };
+ bool can_be_hidden() const override;
+ int get_priority() const override;
- Mode mode;
+ virtual int subgizmos_intersect_ray(const EditorNode3DGizmo *p_gizmo, Camera3D *p_camera, const Vector2 &p_point) const override;
+ virtual Vector<int> subgizmos_intersect_frustum(const EditorNode3DGizmo *p_gizmo, const Camera3D *p_camera, const Vector<Plane> &p_frustum) const override;
+ virtual Transform3D get_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
+ virtual void set_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id, Transform3D p_transform) override;
+ virtual void commit_subgizmos(const EditorNode3DGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel = false) override;
- Button *button_create = nullptr;
- Button *button_edit = nullptr;
+ NavigationObstacle3DGizmoPlugin();
+};
+
+class NavigationObstacle3DEditorPlugin : public EditorPlugin {
+ GDCLASS(NavigationObstacle3DEditorPlugin, EditorPlugin);
+
+ Ref<NavigationObstacle3DGizmoPlugin> obstacle_3d_gizmo_plugin;
+
+ NavigationObstacle3D *obstacle_node = nullptr;
Ref<StandardMaterial3D> line_material;
Ref<StandardMaterial3D> handle_material;
- Panel *panel = nullptr;
- NavigationObstacle3D *obstacle_node = nullptr;
- Ref<ImmediateMesh> point_lines_mesh;
- MeshInstance3D *point_lines_meshinstance = nullptr;
- MeshInstance3D *point_handles_meshinstance = nullptr;
- Ref<ArrayMesh> point_handle_mesh;
+ RID point_lines_mesh_rid;
+ RID point_lines_instance_rid;
+ RID point_handle_mesh_rid;
+ RID point_handles_instance_rid;
- MenuButton *options = nullptr;
+public:
+ enum Mode {
+ MODE_CREATE = 0,
+ MODE_EDIT,
+ MODE_DELETE,
+ ACTION_FLIP,
+ ACTION_CLEAR,
+ };
- int edited_point = 0;
- Vector2 edited_point_pos;
- PackedVector2Array pre_move_edit;
- PackedVector2Array wip;
- bool wip_active;
- bool snap_ignore;
+private:
+ int mode = MODE_EDIT;
- float prev_depth = 0.0f;
+ int edited_point = 0;
+ Vector3 edited_point_pos;
+ Vector<Vector3> pre_move_edit;
+ Vector<Vector3> wip_vertices;
+ bool wip_active = false;
+ bool snap_ignore = false;
void _wip_close();
- void _polygon_draw();
- void _menu_option(int p_option);
+ void _wip_cancel();
+ void _update_theme();
+
+ Button *button_create = nullptr;
+ Button *button_edit = nullptr;
+ Button *button_delete = nullptr;
+ Button *button_flip = nullptr;
+ Button *button_clear = nullptr;
- PackedVector2Array _get_polygon();
- void _set_polygon(const PackedVector2Array &p_poly);
+ ConfirmationDialog *button_clear_dialog = nullptr;
protected:
void _notification(int p_what);
void _node_removed(Node *p_node);
- static void _bind_methods();
public:
- virtual EditorPlugin::AfterGUIInput forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event);
- void edit(Node *p_node);
- NavigationObstacle3DEditor();
- ~NavigationObstacle3DEditor();
-};
+ HBoxContainer *obstacle_editor = nullptr;
+ static NavigationObstacle3DEditorPlugin *singleton;
-class NavigationObstacle3DEditorPlugin : public EditorPlugin {
- GDCLASS(NavigationObstacle3DEditorPlugin, EditorPlugin);
+ void redraw();
- NavigationObstacle3DEditor *obstacle_editor = nullptr;
+ void set_mode(int p_mode);
+ int get_mode() { return mode; }
-public:
- virtual EditorPlugin::AfterGUIInput forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return obstacle_editor->forward_3d_gui_input(p_camera, p_event); }
+ void action_flip_vertices();
+ void action_clear_vertices();
+
+ virtual EditorPlugin::AfterGUIInput forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override;
- virtual String get_name() const override { return "NavigationObstacle3DEditor"; }
+ virtual String get_name() const override { return "NavigationObstacle3D"; }
bool has_main_screen() const override { return false; }
virtual void edit(Object *p_object) override;
virtual bool handles(Object *p_object) const override;
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index 8aff3c9aec..b716e925cb 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -292,14 +292,11 @@ void EditorNode3DGizmo::add_vertices(const Vector<Vector3> &p_vertices, const Re
Vector<Color> color;
color.resize(p_vertices.size());
+ const Color vertex_color = (is_selected() ? Color(1, 1, 1, 0.8) : Color(1, 1, 1, 0.2)) * p_modulate;
{
Color *w = color.ptrw();
for (int i = 0; i < p_vertices.size(); i++) {
- if (is_selected()) {
- w[i] = Color(1, 1, 1, 0.8) * p_modulate;
- } else {
- w[i] = Color(1, 1, 1, 0.2) * p_modulate;
- }
+ w[i] = vertex_color;
}
}
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 810d1674ca..fed04a3754 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -92,6 +92,7 @@
#include "scene/gui/center_container.h"
#include "scene/gui/color_picker.h"
#include "scene/gui/flow_container.h"
+#include "scene/gui/separator.h"
#include "scene/gui/split_container.h"
#include "scene/gui/subviewport_container.h"
#include "scene/resources/3d/sky_material.h"
@@ -3265,7 +3266,7 @@ void Node3DEditorViewport::_draw() {
if (message_time > 0) {
Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));
int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));
- Point2 msgpos = Point2(5, get_size().y - 20);
+ Point2 msgpos = Point2(10 * EDSCALE, get_size().y - 14 * EDSCALE);
font->draw_string(ci, msgpos + Point2(1, 1), message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(0, 0, 0, 0.8));
font->draw_string(ci, msgpos + Point2(-1, -1), message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(0, 0, 0, 0.8));
font->draw_string(ci, msgpos, message, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(1, 1, 1, 1));
@@ -8818,7 +8819,12 @@ Node3DEditor::Node3DEditor() {
ED_SHORTCUT("spatial_editor/focus_origin", TTR("Focus Origin"), Key::O);
ED_SHORTCUT("spatial_editor/focus_selection", TTR("Focus Selection"), Key::F);
ED_SHORTCUT_ARRAY("spatial_editor/align_transform_with_view", TTR("Align Transform with View"),
- { int32_t(KeyModifierMask::ALT | KeyModifierMask::CMD_OR_CTRL | Key::KP_0), int32_t(KeyModifierMask::ALT | KeyModifierMask::CMD_OR_CTRL | Key::M) });
+ { int32_t(KeyModifierMask::ALT | KeyModifierMask::CTRL | Key::KP_0),
+ int32_t(KeyModifierMask::ALT | KeyModifierMask::CTRL | Key::M),
+ int32_t(KeyModifierMask::ALT | KeyModifierMask::CTRL | Key::G) });
+ ED_SHORTCUT_OVERRIDE_ARRAY("spatial_editor/align_transform_with_view", "macos",
+ { int32_t(KeyModifierMask::ALT | KeyModifierMask::META | Key::KP_0),
+ int32_t(KeyModifierMask::ALT | KeyModifierMask::META | Key::G) });
ED_SHORTCUT("spatial_editor/align_rotation_with_view", TTR("Align Rotation with View"), KeyModifierMask::ALT + KeyModifierMask::CMD_OR_CTRL + Key::F);
ED_SHORTCUT("spatial_editor/freelook_toggle", TTR("Toggle Freelook"), KeyModifierMask::SHIFT + Key::F);
ED_SHORTCUT("spatial_editor/decrease_fov", TTR("Decrease Field of View"), KeyModifierMask::CMD_OR_CTRL + Key::EQUAL); // Usually direct access key for `KEY_PLUS`.
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index 3a4b3a0ea2..de4ab828bc 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -277,8 +277,15 @@ void Path3DGizmo::redraw() {
Ref<StandardMaterial3D> path_tilt_material = gizmo_plugin->get_material("path_tilt_material", this);
Ref<StandardMaterial3D> path_tilt_muted_material = gizmo_plugin->get_material("path_tilt_muted_material", this);
Ref<StandardMaterial3D> handles_material = gizmo_plugin->get_material("handles");
+ Ref<StandardMaterial3D> first_pt_handle_material = gizmo_plugin->get_material("first_pt_handle");
+ Ref<StandardMaterial3D> last_pt_handle_material = gizmo_plugin->get_material("last_pt_handle");
+ Ref<StandardMaterial3D> closed_pt_handle_material = gizmo_plugin->get_material("closed_pt_handle");
Ref<StandardMaterial3D> sec_handles_material = gizmo_plugin->get_material("sec_handles");
+ first_pt_handle_material->set_albedo(Color(0.2, 1.0, 0.0));
+ last_pt_handle_material->set_albedo(Color(1.0, 0.2, 0.0));
+ closed_pt_handle_material->set_albedo(Color(1.0, 0.8, 0.0));
+
Ref<Curve3D> c = path->get_curve();
if (c.is_null()) {
return;
@@ -369,7 +376,7 @@ void Path3DGizmo::redraw() {
info.point_idx = idx;
// Collect in-handles except for the first point.
- if (idx > 0 && Path3DEditorPlugin::singleton->curve_edit_curve->is_pressed()) {
+ if (idx > (c->is_closed() ? -1 : 0) && Path3DEditorPlugin::singleton->curve_edit_curve->is_pressed()) {
const Vector3 in = c->get_point_in(idx);
info.type = HandleType::HANDLE_TYPE_IN;
@@ -383,7 +390,7 @@ void Path3DGizmo::redraw() {
}
// Collect out-handles except for the last point.
- if (idx < c->get_point_count() - 1 && Path3DEditorPlugin::singleton->curve_edit_curve->is_pressed()) {
+ if (idx < (c->is_closed() ? c->get_point_count() : c->get_point_count() - 1) && Path3DEditorPlugin::singleton->curve_edit_curve->is_pressed()) {
const Vector3 out = c->get_point_out(idx);
info.type = HandleType::HANDLE_TYPE_OUT;
@@ -441,7 +448,42 @@ void Path3DGizmo::redraw() {
}
if (!Path3DEditorPlugin::singleton->curve_edit->is_pressed() && primary_handle_points.size()) {
- add_handles(primary_handle_points, handles_material);
+ // Need to define indices separately.
+ // Point count.
+ const int pc = primary_handle_points.size();
+ Vector<int> idx;
+ idx.resize(pc);
+ int *idx_ptr = idx.ptrw();
+ for (int j = 0; j < pc; j++) {
+ idx_ptr[j] = j;
+ }
+
+ // Initialize arrays for first point.
+ PackedVector3Array first_pt_handle_point;
+ Vector<int> first_pt_id;
+ first_pt_handle_point.append(primary_handle_points[0]);
+ first_pt_id.append(idx[0]);
+
+ // Initialize arrays and add handle for last point if needed.
+ if (pc > 1) {
+ PackedVector3Array last_pt_handle_point;
+ Vector<int> last_pt_id;
+ last_pt_handle_point.append(primary_handle_points[pc - 1]);
+ last_pt_id.append(idx[pc - 1]);
+ primary_handle_points.remove_at(pc - 1);
+ idx.remove_at(pc - 1);
+ add_handles(last_pt_handle_point, c->is_closed() ? handles_material : last_pt_handle_material, last_pt_id);
+ }
+
+ // Add handle for first point.
+ primary_handle_points.remove_at(0);
+ idx.remove_at(0);
+ add_handles(first_pt_handle_point, c->is_closed() ? closed_pt_handle_material : first_pt_handle_material, first_pt_id);
+
+ // Add handles for remaining intermediate points.
+ if (!primary_handle_points.is_empty()) {
+ add_handles(primary_handle_points, handles_material, idx);
+ }
}
if (secondary_handle_points.size()) {
add_handles(secondary_handle_points, sec_handles_material, collected_secondary_handle_ids, false, true);
@@ -469,7 +511,7 @@ Path3DGizmo::Path3DGizmo(Path3D *p_path, float p_disk_size) {
Path3DEditorPlugin::singleton->curve_edit_curve->connect(SceneStringName(pressed), callable_mp(this, &Path3DGizmo::redraw));
Path3DEditorPlugin::singleton->curve_create->connect(SceneStringName(pressed), callable_mp(this, &Path3DGizmo::redraw));
Path3DEditorPlugin::singleton->curve_del->connect(SceneStringName(pressed), callable_mp(this, &Path3DGizmo::redraw));
- Path3DEditorPlugin::singleton->curve_close->connect(SceneStringName(pressed), callable_mp(this, &Path3DGizmo::redraw));
+ Path3DEditorPlugin::singleton->curve_closed->connect(SceneStringName(pressed), callable_mp(this, &Path3DGizmo::redraw));
}
EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
@@ -696,7 +738,7 @@ void Path3DEditorPlugin::_mode_changed(int p_mode) {
Node3DEditor::get_singleton()->clear_subgizmo_selection();
}
-void Path3DEditorPlugin::_close_curve() {
+void Path3DEditorPlugin::_toggle_closed_curve() {
Ref<Curve3D> c = path->get_curve();
if (c.is_null()) {
return;
@@ -704,13 +746,10 @@ void Path3DEditorPlugin::_close_curve() {
if (c->get_point_count() < 2) {
return;
}
- if (c->get_point_position(0) == c->get_point_position(c->get_point_count() - 1)) {
- return;
- }
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
- ur->create_action(TTR("Close Curve"));
- ur->add_do_method(c.ptr(), "add_point", c->get_point_position(0), c->get_point_in(0), c->get_point_out(0), -1);
- ur->add_undo_method(c.ptr(), "remove_point", c->get_point_count());
+ ur->create_action(TTR("Toggle Open/Closed Curve"));
+ ur->add_do_method(c.ptr(), "set_closed", !c.ptr()->is_closed());
+ ur->add_undo_method(c.ptr(), "set_closed", c.ptr()->is_closed());
ur->commit_action();
}
@@ -771,6 +810,7 @@ void Path3DEditorPlugin::_clear_curve_points() {
return;
}
Ref<Curve3D> curve = path->get_curve();
+ curve->set_closed(false);
curve->clear_points();
}
@@ -795,7 +835,7 @@ void Path3DEditorPlugin::_update_theme() {
curve_edit_tilt->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveTilt")));
curve_create->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveCreate")));
curve_del->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveDelete")));
- curve_close->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveClose")));
+ curve_closed->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("CurveClose")));
curve_clear_points->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("Clear")));
create_curve_button->set_button_icon(topmenu_bar->get_editor_theme_icon(SNAME("Curve3D")));
}
@@ -872,12 +912,12 @@ Path3DEditorPlugin::Path3DEditorPlugin() {
toolbar->add_child(curve_del);
curve_del->connect(SceneStringName(pressed), callable_mp(this, &Path3DEditorPlugin::_mode_changed).bind(MODE_DELETE));
- curve_close = memnew(Button);
- curve_close->set_theme_type_variation("FlatButton");
- curve_close->set_focus_mode(Control::FOCUS_NONE);
- curve_close->set_tooltip_text(TTR("Close Curve"));
- toolbar->add_child(curve_close);
- curve_close->connect(SceneStringName(pressed), callable_mp(this, &Path3DEditorPlugin::_close_curve));
+ curve_closed = memnew(Button);
+ curve_closed->set_theme_type_variation("FlatButton");
+ curve_closed->set_focus_mode(Control::FOCUS_NONE);
+ curve_closed->set_tooltip_text(TTR("Close Curve"));
+ toolbar->add_child(curve_closed);
+ curve_closed->connect(SceneStringName(pressed), callable_mp(this, &Path3DEditorPlugin::_toggle_closed_curve));
curve_clear_points = memnew(Button);
curve_clear_points->set_theme_type_variation("FlatButton");
@@ -943,6 +983,14 @@ void Path3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Ref<Curve3D> curve = path->get_curve();
Ref<StandardMaterial3D> handle_material = get_material("handles", p_gizmo);
+ Ref<StandardMaterial3D> first_pt_handle_material = get_material("first_pt_handle", p_gizmo);
+ Ref<StandardMaterial3D> last_pt_handle_material = get_material("last_pt_handle", p_gizmo);
+ Ref<StandardMaterial3D> closed_pt_handle_material = get_material("closed_pt_handle", p_gizmo);
+
+ first_pt_handle_material->set_albedo(Color(0.2, 1.0, 0.0));
+ last_pt_handle_material->set_albedo(Color(1.0, 0.2, 0.0));
+ closed_pt_handle_material->set_albedo(Color(1.0, 0.8, 0.0));
+
PackedVector3Array handles;
if (Path3DEditorPlugin::singleton->curve_edit->is_pressed()) {
@@ -955,7 +1003,37 @@ void Path3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
if (handles.size()) {
- p_gizmo->add_vertices(handles, handle_material, Mesh::PRIMITIVE_POINTS);
+ // Point count.
+ const int pc = handles.size();
+
+ // Initialize arrays for first point.
+ PackedVector3Array first_pt;
+ first_pt.append(handles[0]);
+
+ // Initialize arrays and add handle for last point if needed.
+ if (pc > 1) {
+ PackedVector3Array last_pt;
+ last_pt.append(handles[handles.size() - 1]);
+ handles.remove_at(handles.size() - 1);
+ if (curve->is_closed()) {
+ p_gizmo->add_vertices(last_pt, handle_material, Mesh::PRIMITIVE_POINTS);
+ } else {
+ p_gizmo->add_vertices(last_pt, last_pt_handle_material, Mesh::PRIMITIVE_POINTS);
+ }
+ }
+
+ // Add handle for first point.
+ handles.remove_at(0);
+ if (curve->is_closed()) {
+ p_gizmo->add_vertices(first_pt, closed_pt_handle_material, Mesh::PRIMITIVE_POINTS);
+ } else {
+ p_gizmo->add_vertices(first_pt, first_pt_handle_material, Mesh::PRIMITIVE_POINTS);
+ }
+
+ // Add handles for remaining intermediate points.
+ if (!handles.is_empty()) {
+ p_gizmo->add_vertices(handles, handle_material, Mesh::PRIMITIVE_POINTS);
+ }
}
}
@@ -1072,5 +1150,8 @@ Path3DGizmoPlugin::Path3DGizmoPlugin(float p_disk_size) {
create_material("path_tilt_material", path_tilt_color);
create_material("path_tilt_muted_material", path_tilt_color * 0.7);
create_handle_material("handles", false, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("EditorPathSmoothHandle"), EditorStringName(EditorIcons)));
+ create_handle_material("first_pt_handle", false, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("EditorPathSmoothHandle"), EditorStringName(EditorIcons)));
+ create_handle_material("last_pt_handle", false, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("EditorPathSmoothHandle"), EditorStringName(EditorIcons)));
+ create_handle_material("closed_pt_handle", false, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("EditorPathSmoothHandle"), EditorStringName(EditorIcons)));
create_handle_material("sec_handles", false, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("EditorCurveHandle"), EditorStringName(EditorIcons)));
}
diff --git a/editor/plugins/path_3d_editor_plugin.h b/editor/plugins/path_3d_editor_plugin.h
index 60cb7f940f..3e45c2718f 100644
--- a/editor/plugins/path_3d_editor_plugin.h
+++ b/editor/plugins/path_3d_editor_plugin.h
@@ -120,7 +120,7 @@ class Path3DEditorPlugin : public EditorPlugin {
Button *curve_edit_curve = nullptr;
Button *curve_edit_tilt = nullptr;
Button *curve_del = nullptr;
- Button *curve_close = nullptr;
+ Button *curve_closed = nullptr;
Button *curve_clear_points = nullptr;
MenuButton *handle_menu = nullptr;
@@ -144,7 +144,7 @@ class Path3DEditorPlugin : public EditorPlugin {
void _update_toolbar();
void _mode_changed(int p_mode);
- void _close_curve();
+ void _toggle_closed_curve();
void _handle_option_pressed(int p_option);
bool handle_clicked = false;
bool mirror_handle_angle = true;
diff --git a/editor/plugins/plugin_config_dialog.cpp b/editor/plugins/plugin_config_dialog.cpp
index af9efda939..c3e87c508e 100644
--- a/editor/plugins/plugin_config_dialog.cpp
+++ b/editor/plugins/plugin_config_dialog.cpp
@@ -305,7 +305,7 @@ PluginConfigDialog::PluginConfigDialog() {
grid->add_child(script_name_label);
script_edit = memnew(LineEdit);
- script_edit->set_tooltip_text(TTR("Optional. The path to the script (relative to the add-on folder). If left empty, will default to \"plugin.gd\"."));
+ script_edit->set_tooltip_text(TTR("Optional. The name of the script file. If left empty, will default to the subfolder name."));
script_edit->set_placeholder("\"plugin.gd\" -> res://addons/my_plugin/plugin.gd");
script_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
grid->add_child(script_edit);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 2edc096382..2ed819baf4 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -64,6 +64,8 @@
#include "editor/themes/editor_scale.h"
#include "editor/themes/editor_theme_manager.h"
#include "editor/window_wrapper.h"
+#include "scene/gui/separator.h"
+#include "scene/gui/texture_rect.h"
#include "scene/main/node.h"
#include "scene/main/window.h"
#include "script_text_editor.h"
@@ -2185,8 +2187,6 @@ void ScriptEditor::_update_script_colors() {
continue;
}
- script_list->set_item_custom_bg_color(i, Color(0, 0, 0, 0));
-
if (script_temperature_enabled) {
int pass = n->get_meta("__editor_pass", -1);
if (pass < 0) {
@@ -2212,7 +2212,7 @@ void ScriptEditor::_update_script_names() {
HashSet<Ref<Script>> used;
Node *edited = EditorNode::get_singleton()->get_edited_scene();
- if (edited) {
+ if (edited && EDITOR_GET("text_editor/script_list/highlight_scene_scripts")) {
_find_scripts(edited, edited, used);
}
@@ -2382,7 +2382,7 @@ void ScriptEditor::_update_script_names() {
script_list->set_item_tooltip(index, sedata_filtered[i].tooltip);
script_list->set_item_metadata(index, sedata_filtered[i].index); /* Saving as metadata the script's index in the tab container and not the filtered one */
if (sedata_filtered[i].used) {
- script_list->set_item_custom_bg_color(index, Color(88 / 255.0, 88 / 255.0, 60 / 255.0));
+ script_list->set_item_custom_bg_color(index, Color(.5, .5, .5, .125));
}
if (tab_container->get_current_tab() == sedata_filtered[i].index) {
script_list->select(index);
@@ -4393,28 +4393,28 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
disk_changed = memnew(ConfirmationDialog);
{
- disk_changed->set_title(TTR("Files have been modified on disk"));
+ disk_changed->set_title(TTR("Files have been modified outside Godot"));
VBoxContainer *vbc = memnew(VBoxContainer);
disk_changed->add_child(vbc);
Label *files_are_newer_label = memnew(Label);
- files_are_newer_label->set_text(TTR("The following files are newer on disk."));
+ files_are_newer_label->set_text(TTR("The following files are newer on disk:"));
vbc->add_child(files_are_newer_label);
- Label *what_action_label = memnew(Label);
- what_action_label->set_text(TTR("What action should be taken?:"));
- vbc->add_child(what_action_label);
-
disk_changed_list = memnew(Tree);
vbc->add_child(disk_changed_list);
disk_changed_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
disk_changed_list->set_v_size_flags(SIZE_EXPAND_FILL);
+ Label *what_action_label = memnew(Label);
+ what_action_label->set_text(TTR("What action should be taken?"));
+ vbc->add_child(what_action_label);
+
disk_changed->connect(SceneStringName(confirmed), callable_mp(this, &ScriptEditor::reload_scripts).bind(false));
- disk_changed->set_ok_button_text(TTR("Discard local changes and reload"));
+ disk_changed->set_ok_button_text(TTR("Reload from disk"));
- disk_changed->add_button(TTR("Keep local changes and overwrite"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave");
+ disk_changed->add_button(TTR("Ignore external changes"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave");
disk_changed->connect("custom_action", callable_mp(this, &ScriptEditor::_resave_scripts));
}
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index b45b30b52e..a28d709b15 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -40,6 +40,7 @@
#include "editor/editor_string_names.h"
#include "editor/gui/editor_toaster.h"
#include "editor/themes/editor_scale.h"
+#include "scene/gui/menu_button.h"
#include "scene/gui/rich_text_label.h"
#include "scene/gui/split_container.h"
@@ -282,7 +283,7 @@ void ScriptTextEditor::_warning_clicked(const Variant &p_line) {
CodeEdit *text_editor = code_editor->get_text_editor();
String prev_line = line > 0 ? text_editor->get_line(line - 1) : "";
if (prev_line.contains("@warning_ignore")) {
- const int closing_bracket_idx = prev_line.find(")");
+ const int closing_bracket_idx = prev_line.find_char(')');
const String text_to_insert = ", " + code.quote(quote_style);
text_editor->insert_text(text_to_insert, line - 1, closing_bracket_idx);
} else {
@@ -951,7 +952,7 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
} else if (p_symbol.is_resource_file() || p_symbol.begins_with("uid://")) {
String symbol = p_symbol;
if (symbol.begins_with("uid://")) {
- symbol = ResourceUID::get_singleton()->get_id_path(ResourceUID::get_singleton()->text_to_id(symbol));
+ symbol = ResourceUID::uid_to_path(symbol);
}
List<String> scene_extensions;
@@ -1205,7 +1206,7 @@ void ScriptTextEditor::_update_connected_methods() {
// Account for inner classes by stripping the class names from the method,
// starting from the right since our inner class might be inside of another inner class.
- int pos = raw_name.rfind(".");
+ int pos = raw_name.rfind_char('.');
if (pos != -1) {
name = raw_name.substr(pos + 1);
}
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index de75ed8c12..b5ddf2f48b 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -48,6 +48,8 @@
#include "scene/gui/option_button.h"
#include "scene/gui/panel_container.h"
#include "scene/gui/scroll_container.h"
+#include "scene/gui/separator.h"
+#include "scene/gui/spin_box.h"
#include "scene/gui/split_container.h"
#include "scene/gui/tab_bar.h"
#include "scene/gui/tab_container.h"
diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp
index ea5e8a8ad7..3790b23f76 100644
--- a/editor/plugins/theme_editor_preview.cpp
+++ b/editor/plugins/theme_editor_preview.cpp
@@ -41,9 +41,15 @@
#include "scene/gui/check_button.h"
#include "scene/gui/color_picker.h"
#include "scene/gui/color_rect.h"
+#include "scene/gui/label.h"
#include "scene/gui/margin_container.h"
+#include "scene/gui/menu_button.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/panel.h"
#include "scene/gui/progress_bar.h"
#include "scene/gui/scroll_container.h"
+#include "scene/gui/separator.h"
+#include "scene/gui/spin_box.h"
#include "scene/gui/tab_container.h"
#include "scene/gui/text_edit.h"
#include "scene/gui/tree.h"
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index 34e24c1424..941d44c85e 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -1699,7 +1699,7 @@ void TileSetAtlasSourceEditor::_menu_option(int p_option) {
void TileSetAtlasSourceEditor::shortcut_input(const Ref<InputEvent> &p_event) {
// Check for shortcuts.
- if (ED_IS_SHORTCUT("tiles_editor/delete_tile", p_event)) {
+ if (ED_IS_SHORTCUT("tiles_editor/delete", p_event)) {
if (tools_button_group->get_pressed_button() == tool_select_button && !selection.is_empty()) {
_menu_option(TILE_DELETE);
accept_event();
@@ -2711,7 +2711,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tile_atlas_control_unscaled->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
alternative_tile_popup_menu = memnew(PopupMenu);
- alternative_tile_popup_menu->add_shortcut(ED_SHORTCUT("tiles_editor/delete_tile", TTR("Delete"), Key::KEY_DELETE), TILE_DELETE);
+ alternative_tile_popup_menu->add_shortcut(ED_GET_SHORTCUT("tiles_editor/delete"), TILE_DELETE);
alternative_tile_popup_menu->connect(SceneStringName(id_pressed), callable_mp(this, &TileSetAtlasSourceEditor::_menu_option));
tile_atlas_view->add_child(alternative_tile_popup_menu);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 9c1befa144..69492081e0 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -59,6 +59,7 @@
#include "scene/gui/rich_text_label.h"
#include "scene/gui/separator.h"
#include "scene/gui/split_container.h"
+#include "scene/gui/texture_rect.h"
#include "scene/gui/tree.h"
#include "scene/gui/view_panner.h"
#include "scene/main/window.h"
@@ -1985,6 +1986,67 @@ bool VisualShaderEditor::_update_preview_parameter_tree() {
return found;
}
+void VisualShaderEditor::_preview_tools_menu_option(int p_idx) {
+ ShaderMaterial *src_mat = nullptr;
+
+ if (p_idx == COPY_PARAMS_FROM_MATERIAL || p_idx == PASTE_PARAMS_TO_MATERIAL) {
+ for (int i = EditorNode::get_singleton()->get_editor_selection_history()->get_path_size() - 1; i >= 0; i--) {
+ Object *object = ObjectDB::get_instance(EditorNode::get_singleton()->get_editor_selection_history()->get_path_object(i));
+ ShaderMaterial *src_mat2;
+ if (!object) {
+ continue;
+ }
+ if (object->has_method("get_material_override")) { // Trying to get material from MeshInstance.
+ src_mat2 = Object::cast_to<ShaderMaterial>(object->call("get_material_override"));
+ } else if (object->has_method("get_material")) { // From CanvasItem/Node2D.
+ src_mat2 = Object::cast_to<ShaderMaterial>(object->call("get_material"));
+ } else {
+ src_mat2 = Object::cast_to<ShaderMaterial>(object);
+ }
+
+ if (src_mat2 && src_mat2->get_shader().is_valid() && src_mat2->get_shader() == visual_shader) {
+ src_mat = src_mat2;
+ break;
+ }
+ }
+ }
+
+ switch (p_idx) {
+ case COPY_PARAMS_FROM_MATERIAL:
+ if (src_mat) {
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->create_action(TTR("Copy Preview Shader Parameters From Material"));
+
+ List<PropertyInfo> params;
+ preview_material->get_shader()->get_shader_uniform_list(&params);
+ for (const PropertyInfo &E : params) {
+ undo_redo->add_do_method(visual_shader.ptr(), "_set_preview_shader_parameter", E.name, src_mat->get_shader_parameter(E.name));
+ undo_redo->add_undo_method(visual_shader.ptr(), "_set_preview_shader_parameter", E.name, preview_material->get_shader_parameter(E.name));
+ }
+
+ undo_redo->commit_action();
+ }
+ break;
+ case PASTE_PARAMS_TO_MATERIAL:
+ if (src_mat) {
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->create_action(TTR("Paste Preview Shader Parameters To Material"));
+
+ List<PropertyInfo> params;
+ preview_material->get_shader()->get_shader_uniform_list(&params);
+ for (const PropertyInfo &E : params) {
+ undo_redo->add_do_method(src_mat, "set_shader_parameter", E.name, preview_material->get_shader_parameter(E.name));
+ undo_redo->add_undo_method(src_mat, "set_shader_parameter", E.name, src_mat->get_shader_parameter(E.name));
+ }
+
+ undo_redo->commit_action();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
void VisualShaderEditor::_clear_preview_param() {
selected_param_id = "";
current_prop = nullptr;
@@ -4064,6 +4126,7 @@ void VisualShaderEditor::_connection_request(const String &p_from, int p_from_in
int from = p_from.to_int();
int to = p_to.to_int();
+ bool swap = last_to_node != -1 && Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL);
if (!visual_shader->can_connect_nodes(type, from, p_from_index, to, p_to_index)) {
return;
@@ -4081,6 +4144,14 @@ void VisualShaderEditor::_connection_request(const String &p_from, int p_from_in
undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
undo_redo->add_do_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
undo_redo->add_undo_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, E.to_node, E.to_port);
+
+ if (swap) {
+ undo_redo->add_do_method(visual_shader.ptr(), "connect_nodes", type, E.from_node, E.from_port, last_to_node, last_to_port);
+ undo_redo->add_undo_method(visual_shader.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, last_to_node, last_to_port);
+ undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, E.from_node, E.from_port, last_to_node, last_to_port);
+ undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, E.from_node, E.from_port, last_to_node, last_to_port);
+ }
+ break;
}
}
@@ -4094,6 +4165,9 @@ void VisualShaderEditor::_connection_request(const String &p_from, int p_from_in
undo_redo->add_do_method(graph_plugin.ptr(), "update_node", (int)type, to);
undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", (int)type, to);
undo_redo->commit_action();
+
+ last_to_node = -1;
+ last_to_port = -1;
}
void VisualShaderEditor::_disconnection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) {
@@ -4104,6 +4178,11 @@ void VisualShaderEditor::_disconnection_request(const String &p_from, int p_from
int from = p_from.to_int();
int to = p_to.to_int();
+ last_to_node = to;
+ last_to_port = p_to_index;
+
+ info_label->show();
+
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Nodes Disconnected"));
undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);
@@ -4115,6 +4194,10 @@ void VisualShaderEditor::_disconnection_request(const String &p_from, int p_from
undo_redo->commit_action();
}
+void VisualShaderEditor::_connection_drag_ended() {
+ info_label->hide();
+}
+
void VisualShaderEditor::_connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position) {
from_node = p_from.to_int();
from_slot = p_from_slot;
@@ -5019,8 +5102,11 @@ void VisualShaderEditor::_param_property_changed(const String &p_property, const
void VisualShaderEditor::_update_current_param() {
if (current_prop != nullptr) {
String name = current_prop->get_meta("id");
- preview_material->set("shader_parameter/" + name, visual_shader->_get_preview_shader_parameter(name));
-
+ if (visual_shader->_has_preview_shader_parameter(name)) {
+ preview_material->set("shader_parameter/" + name, visual_shader->_get_preview_shader_parameter(name));
+ } else {
+ preview_material->set("shader_parameter/" + name, Variant());
+ }
current_prop->update_property();
current_prop->update_editor_property_status();
current_prop->update_cache();
@@ -5159,6 +5245,7 @@ void VisualShaderEditor::_notification(int p_what) {
}
tools->set_button_icon(get_editor_theme_icon(SNAME("Tools")));
+ preview_tools->set_button_icon(get_editor_theme_icon(SNAME("Tools")));
if (is_visible_in_tree()) {
_update_graph();
@@ -6305,6 +6392,7 @@ VisualShaderEditor::VisualShaderEditor() {
graph->connect(SceneStringName(gui_input), callable_mp(this, &VisualShaderEditor::_graph_gui_input));
graph->connect("connection_to_empty", callable_mp(this, &VisualShaderEditor::_connection_to_empty));
graph->connect("connection_from_empty", callable_mp(this, &VisualShaderEditor::_connection_from_empty));
+ graph->connect("connection_drag_ended", callable_mp(this, &VisualShaderEditor::_connection_drag_ended));
graph->connect(SceneStringName(visibility_changed), callable_mp(this, &VisualShaderEditor::_visibility_changed));
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SCALAR, VisualShaderNode::PORT_TYPE_SCALAR_INT);
@@ -6365,6 +6453,13 @@ VisualShaderEditor::VisualShaderEditor() {
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShaderNode::PORT_TYPE_TRANSFORM);
graph->add_valid_connection_type(VisualShaderNode::PORT_TYPE_SAMPLER, VisualShaderNode::PORT_TYPE_SAMPLER);
+ info_label = memnew(Label);
+ info_label->set_text(vformat(TTR("Hold %s Key To Swap Connections"), keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL)));
+ info_label->set_anchors_and_offsets_preset(Control::PRESET_BOTTOM_WIDE, PRESET_MODE_MINSIZE, 20);
+ info_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ info_label->hide();
+ graph->get_top_layer()->add_child(info_label);
+
PanelContainer *toolbar_panel = static_cast<PanelContainer *>(graph->get_menu_hbox()->get_parent());
toolbar_panel->set_anchors_and_offsets_preset(Control::PRESET_TOP_WIDE, PRESET_MODE_MINSIZE, 10);
toolbar_panel->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
@@ -6555,11 +6650,21 @@ VisualShaderEditor::VisualShaderEditor() {
VBoxContainer *params_vbox = memnew(VBoxContainer);
preview_split->add_child(params_vbox);
+ HBoxContainer *filter_hbox = memnew(HBoxContainer);
+ params_vbox->add_child(filter_hbox);
+
param_filter = memnew(LineEdit);
+ filter_hbox->add_child(param_filter);
param_filter->connect(SceneStringName(text_changed), callable_mp(this, &VisualShaderEditor::_param_filter_changed));
param_filter->set_h_size_flags(SIZE_EXPAND_FILL);
param_filter->set_placeholder(TTR("Filter Parameters"));
- params_vbox->add_child(param_filter);
+
+ preview_tools = memnew(MenuButton);
+ filter_hbox->add_child(preview_tools);
+ preview_tools->set_tooltip_text(TTR("Options"));
+ preview_tools->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &VisualShaderEditor::_preview_tools_menu_option));
+ preview_tools->get_popup()->add_item(TTR("Copy Parameters From Material"), COPY_PARAMS_FROM_MATERIAL);
+ preview_tools->get_popup()->add_item(TTR("Paste Parameters To Material"), PASTE_PARAMS_TO_MATERIAL);
ScrollContainer *sc = memnew(ScrollContainer);
sc->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -6775,8 +6880,10 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Grayscale", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Grayscale function."), { VisualShaderNodeColorFunc::FUNC_GRAYSCALE }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("HSV2RGB", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Converts HSV vector to RGB equivalent."), { VisualShaderNodeColorFunc::FUNC_HSV2RGB, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("LinearToSRGB", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Converts color from linear to sRGB color space."), { VisualShaderNodeColorFunc::FUNC_LINEAR_TO_SRGB }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("RGB2HSV", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Converts RGB vector to HSV equivalent."), { VisualShaderNodeColorFunc::FUNC_RGB2HSV, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("Sepia", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Sepia function."), { VisualShaderNodeColorFunc::FUNC_SEPIA }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("SRGBToLinear", "Color/Functions", "VisualShaderNodeColorFunc", TTR("Converts color from sRGB to linear color space."), { VisualShaderNodeColorFunc::FUNC_SRGB_TO_LINEAR }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("Burn", "Color/Operators", "VisualShaderNodeColorOp", TTR("Burn operator."), { VisualShaderNodeColorOp::OP_BURN }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("Darken", "Color/Operators", "VisualShaderNodeColorOp", TTR("Darken operator."), { VisualShaderNodeColorOp::OP_DARKEN }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
@@ -6922,7 +7029,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("NodePositionView", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_view", "NODE_POSITION_VIEW"), { "node_position_view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("NodePositionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("PointCoord", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "point_coord", "POINT_COORD"), { "point_coord" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("ScreenUV", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ScreenUV", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Tangent", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "tangent", "TANGENT"), { "tangent" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Vertex", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex", "VERTEX"), { "vertex" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("View", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view", "VIEW"), { "view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
@@ -6940,6 +7047,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("LightIsDirectional", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_is_directional", "LIGHT_IS_DIRECTIONAL"), { "light_is_directional" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Metallic", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "metallic", "METALLIC"), { "metallic" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Roughness", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "roughness", "ROUGHNESS"), { "roughness" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ScreenUV", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Specular", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "specular", "SPECULAR_LIGHT"), { "specular" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("View", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view", "VIEW"), { "view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index d3dc2e7564..6b7c07e5a7 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -221,6 +221,10 @@ class VisualShaderEditor : public ShaderEditor {
Button *code_preview_button = nullptr;
Button *shader_preview_button = nullptr;
+ int last_to_node = -1;
+ int last_to_port = -1;
+ Label *info_label = nullptr;
+
OptionButton *edit_type = nullptr;
OptionButton *edit_type_standard = nullptr;
OptionButton *edit_type_particles = nullptr;
@@ -276,6 +280,7 @@ class VisualShaderEditor : public ShaderEditor {
bool shader_preview_showed = true;
LineEdit *param_filter = nullptr;
+ MenuButton *preview_tools = nullptr;
String selected_param_id;
Tree *parameters = nullptr;
HashMap<String, PropertyInfo> parameter_props;
@@ -318,6 +323,11 @@ class VisualShaderEditor : public ShaderEditor {
COLLAPSE_ALL
};
+ enum PreviewToolsMenuOptions {
+ COPY_PARAMS_FROM_MATERIAL,
+ PASTE_PARAMS_TO_MATERIAL,
+ };
+
#ifdef MINGW_ENABLED
#undef DELETE
#endif
@@ -367,6 +377,7 @@ class VisualShaderEditor : public ShaderEditor {
void _show_add_varying_dialog();
void _show_remove_varying_dialog();
+ void _preview_tools_menu_option(int p_idx);
void _clear_preview_param();
void _update_preview_parameter_list();
bool _update_preview_parameter_tree();
@@ -495,6 +506,7 @@ class VisualShaderEditor : public ShaderEditor {
void _unlink_node_from_parent_frame(int p_node_id);
+ void _connection_drag_ended();
void _connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position);
void _connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position);
bool _check_node_drop_on_connection(const Vector2 &p_position, Ref<GraphEdit::Connection> *r_closest_connection, int *r_node_id = nullptr, int *r_to_port = nullptr);
diff --git a/editor/plugins/voxel_gi_editor_plugin.cpp b/editor/plugins/voxel_gi_editor_plugin.cpp
index 68fe013c08..527138e060 100644
--- a/editor/plugins/voxel_gi_editor_plugin.cpp
+++ b/editor/plugins/voxel_gi_editor_plugin.cpp
@@ -146,15 +146,15 @@ void VoxelGIEditorPlugin::make_visible(bool p_visible) {
EditorProgress *VoxelGIEditorPlugin::tmp_progress = nullptr;
-void VoxelGIEditorPlugin::bake_func_begin(int p_steps) {
+void VoxelGIEditorPlugin::bake_func_begin() {
ERR_FAIL_COND(tmp_progress != nullptr);
- tmp_progress = memnew(EditorProgress("bake_gi", TTR("Bake VoxelGI"), p_steps));
+ tmp_progress = memnew(EditorProgress("bake_gi", TTR("Bake VoxelGI"), 1000, true));
}
-void VoxelGIEditorPlugin::bake_func_step(int p_step, const String &p_description) {
- ERR_FAIL_NULL(tmp_progress);
- tmp_progress->step(p_description, p_step, false);
+bool VoxelGIEditorPlugin::bake_func_step(int p_progress, const String &p_description) {
+ ERR_FAIL_NULL_V(tmp_progress, false);
+ return tmp_progress->step(p_description, p_progress, false);
}
void VoxelGIEditorPlugin::bake_func_end() {
diff --git a/editor/plugins/voxel_gi_editor_plugin.h b/editor/plugins/voxel_gi_editor_plugin.h
index d09822dda6..01a2ab4bd1 100644
--- a/editor/plugins/voxel_gi_editor_plugin.h
+++ b/editor/plugins/voxel_gi_editor_plugin.h
@@ -50,8 +50,8 @@ class VoxelGIEditorPlugin : public EditorPlugin {
EditorFileDialog *probe_file = nullptr;
static EditorProgress *tmp_progress;
- static void bake_func_begin(int p_steps);
- static void bake_func_step(int p_step, const String &p_description);
+ static void bake_func_begin();
+ static bool bake_func_step(int p_progress, const String &p_description);
static void bake_func_end();
void _bake();
diff --git a/editor/pot_generator.cpp b/editor/pot_generator.cpp
index 76b6593f1d..3598a29fec 100644
--- a/editor/pot_generator.cpp
+++ b/editor/pot_generator.cpp
@@ -69,11 +69,16 @@ void POTGenerator::generate_pot(const String &p_file) {
for (int i = 0; i < files.size(); i++) {
Vector<String> msgids;
Vector<Vector<String>> msgids_context_plural;
+
+ Vector<String> msgids_comment;
+ Vector<String> msgids_context_plural_comment;
+
const String &file_path = files[i];
String file_extension = file_path.get_extension();
if (EditorTranslationParser::get_singleton()->can_parse(file_extension)) {
EditorTranslationParser::get_singleton()->get_parser(file_extension)->parse_file(file_path, &msgids, &msgids_context_plural);
+ EditorTranslationParser::get_singleton()->get_parser(file_extension)->get_comments(&msgids_comment, &msgids_context_plural_comment);
} else {
ERR_PRINT("Unrecognized file extension " + file_extension + " in generate_pot()");
return;
@@ -81,16 +86,18 @@ void POTGenerator::generate_pot(const String &p_file) {
for (int j = 0; j < msgids_context_plural.size(); j++) {
const Vector<String> &entry = msgids_context_plural[j];
- _add_new_msgid(entry[0], entry[1], entry[2], file_path);
+ const String &comment = (j < msgids_context_plural_comment.size()) ? msgids_context_plural_comment[j] : String();
+ _add_new_msgid(entry[0], entry[1], entry[2], file_path, comment);
}
for (int j = 0; j < msgids.size(); j++) {
- _add_new_msgid(msgids[j], "", "", file_path);
+ const String &comment = (j < msgids_comment.size()) ? msgids_comment[j] : String();
+ _add_new_msgid(msgids[j], "", "", file_path, comment);
}
}
if (GLOBAL_GET("internationalization/locale/translation_add_builtin_strings_to_pot")) {
for (const Vector<String> &extractable_msgids : get_extractable_message_list()) {
- _add_new_msgid(extractable_msgids[0], extractable_msgids[1], extractable_msgids[2], "");
+ _add_new_msgid(extractable_msgids[0], extractable_msgids[1], extractable_msgids[2], "", "");
}
}
@@ -136,15 +143,25 @@ void POTGenerator::_write_to_pot(const String &p_file) {
String context = v_msgid_data[i].ctx;
String plural = v_msgid_data[i].plural;
const HashSet<String> &locations = v_msgid_data[i].locations;
+ const HashSet<String> &comments = v_msgid_data[i].comments;
// Put the blank line at the start, to avoid a double at the end when closing the file.
file->store_line("");
+ // Write comments.
+ bool is_first_comment = true;
+ for (const String &E : comments) {
+ if (is_first_comment) {
+ file->store_line("#. TRANSLATORS: " + E.replace("\n", "\n#. "));
+ } else {
+ file->store_line("#. " + E.replace("\n", "\n#. "));
+ }
+ is_first_comment = false;
+ }
+
// Write file locations.
for (const String &E : locations) {
- if (!E.is_empty()) {
- file->store_line("#: " + E.trim_prefix("res://").replace("\n", "\\n"));
- }
+ file->store_line("#: " + E.trim_prefix("res://").replace("\n", "\\n"));
}
// Write context.
@@ -199,7 +216,7 @@ void POTGenerator::_write_msgid(Ref<FileAccess> r_file, const String &p_id, bool
}
}
-void POTGenerator::_add_new_msgid(const String &p_msgid, const String &p_context, const String &p_plural, const String &p_location) {
+void POTGenerator::_add_new_msgid(const String &p_msgid, const String &p_context, const String &p_plural, const String &p_location, const String &p_comment) {
// Insert new location if msgid under same context exists already.
if (all_translation_strings.has(p_msgid)) {
Vector<MsgidData> &v_mdata = all_translation_strings[p_msgid];
@@ -208,18 +225,27 @@ void POTGenerator::_add_new_msgid(const String &p_msgid, const String &p_context
if (!v_mdata[i].plural.is_empty() && !p_plural.is_empty() && v_mdata[i].plural != p_plural) {
WARN_PRINT("Redefinition of plural message (msgid_plural), under the same message (msgid) and context (msgctxt)");
}
- v_mdata.write[i].locations.insert(p_location);
+ if (!p_location.is_empty()) {
+ v_mdata.write[i].locations.insert(p_location);
+ }
+ if (!p_comment.is_empty()) {
+ v_mdata.write[i].comments.insert(p_comment);
+ }
return;
}
}
}
- // Add a new entry of msgid, context, plural and location - context and plural might be empty if the inserted msgid doesn't associated
- // context or plurals.
+ // Add a new entry.
MsgidData mdata;
mdata.ctx = p_context;
mdata.plural = p_plural;
- mdata.locations.insert(p_location);
+ if (!p_location.is_empty()) {
+ mdata.locations.insert(p_location);
+ }
+ if (!p_comment.is_empty()) {
+ mdata.comments.insert(p_comment);
+ }
all_translation_strings[p_msgid].push_back(mdata);
}
diff --git a/editor/pot_generator.h b/editor/pot_generator.h
index 8bcb2e5cac..54f4aa0652 100644
--- a/editor/pot_generator.h
+++ b/editor/pot_generator.h
@@ -44,13 +44,14 @@ class POTGenerator {
String ctx;
String plural;
HashSet<String> locations;
+ HashSet<String> comments;
};
// Store msgid as key and the additional data around the msgid - if it's under a context, has plurals and its file locations.
HashMap<String, Vector<MsgidData>> all_translation_strings;
void _write_to_pot(const String &p_file);
void _write_msgid(Ref<FileAccess> r_file, const String &p_id, bool p_plural);
- void _add_new_msgid(const String &p_msgid, const String &p_context, const String &p_plural, const String &p_location);
+ void _add_new_msgid(const String &p_msgid, const String &p_context, const String &p_plural, const String &p_location, const String &p_comment);
#ifdef DEBUG_POT
void _print_all_translation_strings();
diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp
index d08610c93f..edf3ff7296 100644
--- a/editor/project_converter_3_to_4.cpp
+++ b/editor/project_converter_3_to_4.cpp
@@ -1970,7 +1970,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
// -- func c(var a, var b) -> func c(a, b)
if (line.contains("func ") && line.contains("var ")) {
int start = line.find("func ");
- start = line.substr(start).find("(") + start;
+ start = line.substr(start).find_char('(') + start;
int end = get_end_parenthesis(line.substr(start)) + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
@@ -2120,12 +2120,12 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
}
}
// -- func _init(p_x:int).(p_x): -> func _init(p_x:int):\n\tsuper(p_x) Object # https://github.com/godotengine/godot/issues/70542
- if (line.contains(" _init(") && line.rfind(":") > 0) {
+ if (line.contains(" _init(") && line.rfind_char(':') > 0) {
// func _init(p_arg1).(super4, super5, super6)->void:
// ^--^indent ^super_start super_end^
int indent = line.count("\t", 0, line.find("func"));
int super_start = line.find(".(");
- int super_end = line.rfind(")");
+ int super_end = line.rfind_char(')');
if (super_start > 0 && super_end > super_start) {
line = line.substr(0, super_start) + line.substr(super_end + 1) + "\n" + String("\t").repeat(indent + 1) + "super" + line.substr(super_start + 1, super_end - super_start);
}
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 30cf2030bc..eb5e8d2a72 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -34,8 +34,6 @@
#include "core/io/config_file.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
-#include "core/io/resource_saver.h"
-#include "core/io/stream_peer_tls.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/version.h"
@@ -51,12 +49,9 @@
#include "editor/project_manager/project_list.h"
#include "editor/project_manager/project_tag.h"
#include "editor/project_manager/quick_settings_dialog.h"
-#include "editor/themes/editor_icons.h"
#include "editor/themes/editor_scale.h"
#include "editor/themes/editor_theme_manager.h"
#include "main/main.h"
-#include "scene/gui/check_box.h"
-#include "scene/gui/color_rect.h"
#include "scene/gui/flow_container.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/margin_container.h"
@@ -64,7 +59,6 @@
#include "scene/gui/panel_container.h"
#include "scene/gui/rich_text_label.h"
#include "scene/gui/separator.h"
-#include "scene/gui/texture_rect.h"
#include "scene/main/window.h"
#include "scene/theme/theme_db.h"
#include "servers/display_server.h"
@@ -1300,15 +1294,10 @@ ProjectManager::ProjectManager() {
filter_option->connect(SceneStringName(item_selected), callable_mp(this, &ProjectManager::_on_order_option_changed));
hb->add_child(filter_option);
- Vector<String> sort_filter_titles;
- sort_filter_titles.push_back(TTR("Last Edited"));
- sort_filter_titles.push_back(TTR("Name"));
- sort_filter_titles.push_back(TTR("Path"));
- sort_filter_titles.push_back(TTR("Tags"));
-
- for (int i = 0; i < sort_filter_titles.size(); i++) {
- filter_option->add_item(sort_filter_titles[i]);
- }
+ filter_option->add_item(TTR("Last Edited"));
+ filter_option->add_item(TTR("Name"));
+ filter_option->add_item(TTR("Path"));
+ filter_option->add_item(TTR("Tags"));
}
// Project list and its sidebar.
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 89c18143dc..97f1d5d641 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -31,6 +31,7 @@
#include "project_settings_editor.h"
#include "core/config/project_settings.h"
+#include "core/input/input_map.h"
#include "editor/editor_inspector.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
@@ -390,7 +391,7 @@ void ProjectSettingsEditor::_action_added(const String &p_name) {
Dictionary action;
action["events"] = Array();
- action["deadzone"] = 0.2f;
+ action["deadzone"] = InputMap::DEFAULT_DEADZONE;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Input Action"));
diff --git a/editor/register_editor_types.cpp b/editor/register_editor_types.cpp
index c4ebca7308..2d3cbfb1e3 100644
--- a/editor/register_editor_types.cpp
+++ b/editor/register_editor_types.cpp
@@ -52,6 +52,7 @@
#include "editor/filesystem_dock.h"
#include "editor/gui/editor_file_dialog.h"
#include "editor/gui/editor_spin_slider.h"
+#include "editor/gui/editor_toaster.h"
#include "editor/import/3d/resource_importer_obj.h"
#include "editor/import/3d/resource_importer_scene.h"
#include "editor/import/editor_import_plugin.h"
@@ -146,6 +147,7 @@ void register_editor_types() {
GDREGISTER_CLASS(EditorSelection);
GDREGISTER_CLASS(EditorFileDialog);
GDREGISTER_CLASS(EditorSettings);
+ GDREGISTER_ABSTRACT_CLASS(EditorToaster);
GDREGISTER_CLASS(EditorNode3DGizmo);
GDREGISTER_CLASS(EditorNode3DGizmoPlugin);
GDREGISTER_ABSTRACT_CLASS(EditorResourcePreview);
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index 8dd2fe8e4e..8615836ddd 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -144,7 +144,7 @@ void ScriptCreateDialog::_notification(int p_what) {
void ScriptCreateDialog::_path_hbox_sorted() {
if (is_visible()) {
- int filename_start_pos = file_path->get_text().rfind("/") + 1;
+ int filename_start_pos = file_path->get_text().rfind_char('/') + 1;
int filename_end_pos = file_path->get_text().get_basename().length();
if (!is_built_in) {
@@ -359,6 +359,7 @@ void ScriptCreateDialog::_create_new() {
alert->popup_centered();
return;
}
+ EditorNode::get_singleton()->ensure_uid_file(lpath);
}
emit_signal(SNAME("script_created"), scr);
diff --git a/editor/shader_create_dialog.cpp b/editor/shader_create_dialog.cpp
index 2bfe088e7f..33da3dd10c 100644
--- a/editor/shader_create_dialog.cpp
+++ b/editor/shader_create_dialog.cpp
@@ -31,6 +31,7 @@
#include "shader_create_dialog.h"
#include "core/config/project_settings.h"
+#include "editor/editor_node.h"
#include "editor/gui/editor_file_dialog.h"
#include "editor/gui/editor_validation_panel.h"
#include "editor/themes/editor_scale.h"
@@ -102,7 +103,7 @@ void ShaderCreateDialog::_update_language_info() {
void ShaderCreateDialog::_path_hbox_sorted() {
if (is_visible()) {
- int filename_start_pos = initial_base_path.rfind("/") + 1;
+ int filename_start_pos = initial_base_path.rfind_char('/') + 1;
int filename_end_pos = initial_base_path.length();
if (!is_built_in) {
@@ -240,6 +241,7 @@ void fog() {
alert->popup_centered();
return;
}
+ EditorNode::get_singleton()->ensure_uid_file(lpath);
emit_signal(SNAME("shader_include_created"), shader_inc);
} else {
@@ -258,6 +260,7 @@ void fog() {
alert->popup_centered();
return;
}
+ EditorNode::get_singleton()->ensure_uid_file(lpath);
}
emit_signal(SNAME("shader_created"), shader);
diff --git a/editor/themes/editor_theme_manager.cpp b/editor/themes/editor_theme_manager.cpp
index 32079f3753..a4251bfd29 100644
--- a/editor/themes/editor_theme_manager.cpp
+++ b/editor/themes/editor_theme_manager.cpp
@@ -2506,6 +2506,7 @@ void EditorThemeManager::_populate_editor_styles(const Ref<EditorTheme> &p_theme
p_theme->set_color("transition_icon_disabled_color", "GraphStateMachine", Color(1, 1, 1, 0.2));
p_theme->set_color("highlight_color", "GraphStateMachine", p_config.accent_color);
p_theme->set_color("highlight_disabled_color", "GraphStateMachine", p_config.accent_color * Color(1, 1, 1, 0.6));
+ p_theme->set_color("focus_color", "GraphStateMachine", p_config.accent_color);
p_theme->set_color("guideline_color", "GraphStateMachine", p_config.font_color * Color(1, 1, 1, 0.3));
p_theme->set_color("playback_color", "GraphStateMachine", p_config.font_color);
diff --git a/main/main.cpp b/main/main.cpp
index bdadd24d35..123114ce8d 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -733,6 +733,7 @@ Error Main::test_setup() {
physics_server_2d_manager = memnew(PhysicsServer2DManager);
// From `Main::setup2()`.
+ register_early_core_singletons();
initialize_modules(MODULE_INITIALIZATION_LEVEL_CORE);
register_core_extensions();
@@ -1598,7 +1599,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
} else if (arg.ends_with("project.godot")) {
String path;
String file = arg;
- int sep = MAX(file.rfind("/"), file.rfind("\\"));
+ int sep = MAX(file.rfind_char('/'), file.rfind_char('\\'));
if (sep == -1) {
path = ".";
} else {
@@ -1801,13 +1802,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
} else if (arg == "--" || arg == "++") {
adding_user_args = true;
} else {
- if (!FileAccess::exists(arg) && !DirAccess::exists(arg)) {
- // Warn if the argument isn't recognized by Godot *and* the file/folder
- // specified by a positional argument doesn't exist.
- // This allows projects to read file or folder paths as a positional argument
- // without printing a warning, as this scenario can't make use of user command line arguments.
- WARN_PRINT(vformat("Unknown command line argument \"%s\". User arguments should be passed after a -- or ++ separator, e.g. \"-- %s\".", arg, arg));
- }
main_args.push_back(arg);
}
@@ -1876,12 +1870,55 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
if (editor) {
Engine::get_singleton()->set_editor_hint(true);
Engine::get_singleton()->set_extension_reloading_enabled(true);
+
+ main_args.push_back("--editor");
+ if (!init_windowed && !init_fullscreen) {
+ init_maximized = true;
+ window_mode = DisplayServer::WINDOW_MODE_MAXIMIZED;
+ }
+ }
+
+ if (!project_manager && !editor) {
+ // If we didn't find a project, we fall back to the project manager.
+ project_manager = !found_project && !cmdline_tool;
+ }
+
+ if (project_manager) {
+ Engine::get_singleton()->set_project_manager_hint(true);
}
#endif
+ OS::get_singleton()->set_cmdline(execpath, main_args, user_args);
+
+ Engine::get_singleton()->set_physics_ticks_per_second(GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "physics/common/physics_ticks_per_second", PROPERTY_HINT_RANGE, "1,1000,1"), 60));
+ Engine::get_singleton()->set_max_physics_steps_per_frame(GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "physics/common/max_physics_steps_per_frame", PROPERTY_HINT_RANGE, "1,100,1"), 8));
+ Engine::get_singleton()->set_physics_jitter_fix(GLOBAL_DEF("physics/common/physics_jitter_fix", 0.5));
+ Engine::get_singleton()->set_max_fps(GLOBAL_DEF(PropertyInfo(Variant::INT, "application/run/max_fps", PROPERTY_HINT_RANGE, "0,1000,1"), 0));
+ if (max_fps >= 0) {
+ Engine::get_singleton()->set_max_fps(max_fps);
+ }
+
// Initialize user data dir.
OS::get_singleton()->ensure_user_data_dir();
+ OS::get_singleton()->set_low_processor_usage_mode(GLOBAL_DEF("application/run/low_processor_mode", false));
+ OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(
+ GLOBAL_DEF(PropertyInfo(Variant::INT, "application/run/low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "0,33200,1,or_greater"), 6900)); // Roughly 144 FPS
+
+ GLOBAL_DEF("application/run/delta_smoothing", true);
+ if (!delta_smoothing_override) {
+ OS::get_singleton()->set_delta_smoothing(GLOBAL_GET("application/run/delta_smoothing"));
+ }
+
+ GLOBAL_DEF("debug/settings/stdout/print_fps", false);
+ GLOBAL_DEF("debug/settings/stdout/print_gpu_profile", false);
+ GLOBAL_DEF("debug/settings/stdout/verbose_stdout", false);
+ GLOBAL_DEF("debug/settings/physics_interpolation/enable_warnings", true);
+ if (!OS::get_singleton()->_verbose_stdout) { // Not manually overridden.
+ OS::get_singleton()->_verbose_stdout = GLOBAL_GET("debug/settings/stdout/verbose_stdout");
+ }
+
+ register_early_core_singletons();
initialize_modules(MODULE_INITIALIZATION_LEVEL_CORE);
register_core_extensions(); // core extensions must be registered after globals setup and before display
@@ -1906,20 +1943,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
#ifdef TOOLS_ENABLED
if (editor) {
packed_data->set_disabled(true);
- main_args.push_back("--editor");
- if (!init_windowed && !init_fullscreen) {
- init_maximized = true;
- window_mode = DisplayServer::WINDOW_MODE_MAXIMIZED;
- }
- }
-
- if (!project_manager && !editor) {
- // If we didn't find a project, we fall back to the project manager.
- project_manager = !found_project && !cmdline_tool;
- }
-
- if (project_manager) {
- Engine::get_singleton()->set_project_manager_hint(true);
}
#endif
@@ -1991,8 +2014,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
Logger::set_flush_stdout_on_print(GLOBAL_GET("application/run/flush_stdout_on_print"));
- OS::get_singleton()->set_cmdline(execpath, main_args, user_args);
-
{
String driver_hints = "";
String driver_hints_with_d3d12 = "";
@@ -2551,10 +2572,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
window_vsync_mode = DisplayServer::VSyncMode::VSYNC_DISABLED;
}
}
- Engine::get_singleton()->set_physics_ticks_per_second(GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "physics/common/physics_ticks_per_second", PROPERTY_HINT_RANGE, "1,1000,1"), 60));
- Engine::get_singleton()->set_max_physics_steps_per_frame(GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "physics/common/max_physics_steps_per_frame", PROPERTY_HINT_RANGE, "1,100,1"), 8));
- Engine::get_singleton()->set_physics_jitter_fix(GLOBAL_DEF("physics/common/physics_jitter_fix", 0.5));
- Engine::get_singleton()->set_max_fps(GLOBAL_DEF(PropertyInfo(Variant::INT, "application/run/max_fps", PROPERTY_HINT_RANGE, "0,1000,1"), 0));
GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "audio/driver/output_latency", PROPERTY_HINT_RANGE, "1,100,1"), 15);
// Use a safer default output_latency for web to avoid audio cracking on low-end devices, especially mobile.
@@ -2562,23 +2579,10 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
Engine::get_singleton()->set_audio_output_latency(GLOBAL_GET("audio/driver/output_latency"));
- GLOBAL_DEF("debug/settings/stdout/print_fps", false);
- GLOBAL_DEF("debug/settings/stdout/print_gpu_profile", false);
- GLOBAL_DEF("debug/settings/stdout/verbose_stdout", false);
- GLOBAL_DEF("debug/settings/physics_interpolation/enable_warnings", true);
-
- if (!OS::get_singleton()->_verbose_stdout) { // Not manually overridden.
- OS::get_singleton()->_verbose_stdout = GLOBAL_GET("debug/settings/stdout/verbose_stdout");
- }
-
#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
OS::get_singleton()->set_environment("MVK_CONFIG_LOG_LEVEL", OS::get_singleton()->_verbose_stdout ? "3" : "1"); // 1 = Errors only, 3 = Info
#endif
- if (max_fps >= 0) {
- Engine::get_singleton()->set_max_fps(max_fps);
- }
-
if (frame_delay == 0) {
frame_delay = GLOBAL_DEF(PropertyInfo(Variant::INT, "application/run/frame_delay_msec", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), 0);
if (Engine::get_singleton()->is_editor_hint()) {
@@ -2590,15 +2594,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
Engine::get_singleton()->set_audio_output_latency(audio_output_latency);
}
- OS::get_singleton()->set_low_processor_usage_mode(GLOBAL_DEF("application/run/low_processor_mode", false));
- OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(
- GLOBAL_DEF(PropertyInfo(Variant::INT, "application/run/low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "0,33200,1,or_greater"), 6900)); // Roughly 144 FPS
-
- GLOBAL_DEF("application/run/delta_smoothing", true);
- if (!delta_smoothing_override) {
- OS::get_singleton()->set_delta_smoothing(GLOBAL_GET("application/run/delta_smoothing"));
- }
-
GLOBAL_DEF("display/window/ios/allow_high_refresh_rate", true);
GLOBAL_DEF("display/window/ios/hide_home_indicator", true);
GLOBAL_DEF("display/window/ios/hide_status_bar", true);
@@ -3024,6 +3019,12 @@ Error Main::setup2(bool p_show_boot_logo) {
OS::get_singleton()->benchmark_end_measure("Servers", "Display");
}
+ // Max FPS needs to be set after the DisplayServer is created.
+ RenderingDevice *rd = RenderingDevice::get_singleton();
+ if (rd) {
+ rd->_set_max_fps(engine->get_max_fps());
+ }
+
#ifdef TOOLS_ENABLED
// If the editor is running in windowed mode, ensure the window rect fits
// the screen in case screen count or position has changed.
@@ -3455,7 +3456,7 @@ void Main::setup_boot_logo() {
if (show_logo) { //boot logo!
const bool boot_logo_image = GLOBAL_DEF_BASIC("application/boot_splash/show_image", true);
- const String boot_logo_path = String(GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "application/boot_splash/image", PROPERTY_HINT_FILE, "*.png"), String())).strip_edges();
+ const String boot_logo_path = ResourceUID::ensure_path(GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "application/boot_splash/image", PROPERTY_HINT_FILE, "*.png"), String())).strip_edges();
const bool boot_logo_scale = GLOBAL_DEF_BASIC("application/boot_splash/fullsize", true);
const bool boot_logo_filter = GLOBAL_DEF_BASIC("application/boot_splash/use_filter", true);
@@ -4040,12 +4041,12 @@ int Main::start() {
EditorNode *editor_node = nullptr;
if (editor) {
OS::get_singleton()->benchmark_begin_measure("Startup", "Editor");
- editor_node = memnew(EditorNode);
if (editor_pseudolocalization) {
translation_server->get_editor_domain()->set_pseudolocalization_enabled(true);
}
+ editor_node = memnew(EditorNode);
sml->get_root()->add_child(editor_node);
if (!_export_preset.is_empty()) {
@@ -4150,7 +4151,7 @@ int Main::start() {
local_game_path = "res://" + local_game_path;
} else {
- int sep = local_game_path.rfind("/");
+ int sep = local_game_path.rfind_char('/');
if (sep == -1) {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
@@ -4237,14 +4238,15 @@ int Main::start() {
if (project_manager) {
OS::get_singleton()->benchmark_begin_measure("Startup", "Project Manager");
Engine::get_singleton()->set_editor_hint(true);
- ProjectManager *pmanager = memnew(ProjectManager);
- ProgressDialog *progress_dialog = memnew(ProgressDialog);
- pmanager->add_child(progress_dialog);
if (editor_pseudolocalization) {
translation_server->get_editor_domain()->set_pseudolocalization_enabled(true);
}
+ ProjectManager *pmanager = memnew(ProjectManager);
+ ProgressDialog *progress_dialog = memnew(ProgressDialog);
+ pmanager->add_child(progress_dialog);
+
sml->get_root()->add_child(pmanager);
OS::get_singleton()->benchmark_end_measure("Startup", "Project Manager");
}
diff --git a/main/performance.cpp b/main/performance.cpp
index c73fb62b76..398511995b 100644
--- a/main/performance.cpp
+++ b/main/performance.cpp
@@ -132,11 +132,9 @@ String Performance::get_monitor_name(Monitor p_monitor) const {
PNAME("physics_2d/active_objects"),
PNAME("physics_2d/collision_pairs"),
PNAME("physics_2d/islands"),
-#ifndef _3D_DISABLED
PNAME("physics_3d/active_objects"),
PNAME("physics_3d/collision_pairs"),
PNAME("physics_3d/islands"),
-#endif // _3D_DISABLED
PNAME("audio/driver/output_latency"),
PNAME("navigation/active_maps"),
PNAME("navigation/regions"),
@@ -280,11 +278,9 @@ Performance::MonitorType Performance::get_monitor_type(Monitor p_monitor) const
MONITOR_TYPE_QUANTITY,
MONITOR_TYPE_QUANTITY,
MONITOR_TYPE_QUANTITY,
-#ifndef _3D_DISABLED
MONITOR_TYPE_QUANTITY,
MONITOR_TYPE_QUANTITY,
MONITOR_TYPE_QUANTITY,
-#endif // _3D_DISABLED
MONITOR_TYPE_TIME,
MONITOR_TYPE_QUANTITY,
MONITOR_TYPE_QUANTITY,
diff --git a/methods.py b/methods.py
index 64c3839718..be290f8128 100644
--- a/methods.py
+++ b/methods.py
@@ -1,5 +1,7 @@
+import atexit
import contextlib
import glob
+import math
import os
import re
import subprocess
@@ -8,7 +10,7 @@ from collections import OrderedDict
from enum import Enum
from io import StringIO, TextIOWrapper
from pathlib import Path
-from typing import Generator, List, Optional, Union
+from typing import Generator, List, Optional, Union, cast
# Get the "Godot" folder name ahead of time
base_folder_path = str(os.path.abspath(Path(__file__).parent)) + "/"
@@ -100,6 +102,7 @@ def add_source_files_scu(self, sources, files, allow_gen=False):
subdir = os.path.dirname(files)
subdir = subdir if subdir == "" else subdir + "/"
section_name = self.Dir(subdir).tpath
+ section_name = section_name.replace("\\", "/") # win32
# if the section name is in the hash table?
# i.e. is it part of the SCU build?
global _scu_folders
@@ -409,8 +412,7 @@ def use_windows_spawn_fix(self, platform=None):
"shell": False,
"env": env,
}
- if sys.version_info >= (3, 7, 0):
- popen_args["text"] = True
+ popen_args["text"] = True
proc = subprocess.Popen(cmdline, **popen_args)
_, err = proc.communicate()
rv = proc.wait()
@@ -593,23 +595,6 @@ def glob_recursive(pattern, node="."):
return results
-def add_to_vs_project(env, sources):
- for x in sources:
- fname = env.File(x).path if isinstance(x, str) else env.File(x)[0].path
- pieces = fname.split(".")
- if len(pieces) > 0:
- basename = pieces[0]
- basename = basename.replace("\\\\", "/")
- if os.path.isfile(basename + ".h"):
- env.vs_incs += [basename + ".h"]
- elif os.path.isfile(basename + ".hpp"):
- env.vs_incs += [basename + ".hpp"]
- if os.path.isfile(basename + ".c"):
- env.vs_srcs += [basename + ".c"]
- elif os.path.isfile(basename + ".cpp"):
- env.vs_srcs += [basename + ".cpp"]
-
-
def precious_program(env, program, sources, **args):
program = env.ProgramOriginal(program, sources, **args)
env.Precious(program)
@@ -670,7 +655,9 @@ def detect_darwin_sdk_path(platform, env):
raise
-def is_vanilla_clang(env):
+def is_apple_clang(env):
+ if env["platform"] not in ["macos", "ios"]:
+ return False
if not using_clang(env):
return False
try:
@@ -678,7 +665,7 @@ def is_vanilla_clang(env):
except (subprocess.CalledProcessError, OSError):
print_warning("Couldn't parse CXX environment variable to infer compiler version.")
return False
- return not version.startswith("Apple")
+ return version.startswith("Apple")
def get_compiler_version(env):
@@ -802,159 +789,165 @@ def using_emcc(env):
def show_progress(env):
- if env["ninja"]:
- # Has its own progress/tracking tool that clashes with ours
+ # Progress reporting is not available in non-TTY environments since it messes with the output
+ # (for example, when writing to a file). Ninja has its own progress/tracking tool that clashes
+ # with ours.
+ if not env["progress"] or not sys.stdout.isatty() or env["ninja"]:
return
- import sys
-
- from SCons.Script import AlwaysBuild, Command, Progress
-
- screen = sys.stdout
- # Progress reporting is not available in non-TTY environments since it
- # messes with the output (for example, when writing to a file)
- show_progress = env["progress"] and sys.stdout.isatty()
- node_count = 0
- node_count_max = 0
- node_count_interval = 1
- node_count_fname = str(env.Dir("#")) + "/.scons_node_count"
-
- import math
-
- class cache_progress:
- # The default is 1 GB cache
- def __init__(self, path=None, limit=pow(1024, 3)):
- self.path = path
- self.limit = limit
- if env["verbose"] and path is not None:
- screen.write(
- "Current cache limit is {} (used: {})\n".format(
- self.convert_size(limit), self.convert_size(self.get_size(path))
- )
- )
+ NODE_COUNT_FILENAME = f"{base_folder_path}.scons_node_count"
+
+ class ShowProgress:
+ def __init__(self):
+ self.count = 0
+ self.max = 0
+ try:
+ with open(NODE_COUNT_FILENAME, "r", encoding="utf-8") as f:
+ self.max = int(f.readline())
+ except OSError:
+ pass
+ if self.max == 0:
+ print("NOTE: Performing initial build, progress percentage unavailable!")
def __call__(self, node, *args, **kw):
- nonlocal node_count, node_count_max, node_count_interval, node_count_fname, show_progress
- if show_progress:
- # Print the progress percentage
- node_count += node_count_interval
- if node_count_max > 0 and node_count <= node_count_max:
- screen.write("\r[%3d%%] " % (node_count * 100 / node_count_max))
- screen.flush()
- elif node_count_max > 0 and node_count > node_count_max:
- screen.write("\r[100%] ")
- screen.flush()
- else:
- screen.write("\r[Initial build] ")
- screen.flush()
-
- def convert_size(self, size_bytes):
- if size_bytes == 0:
- return "0 bytes"
- size_name = ("bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
- i = int(math.floor(math.log(size_bytes, 1024)))
- p = math.pow(1024, i)
- s = round(size_bytes / p, 2)
- return "%s %s" % (int(s) if i == 0 else s, size_name[i])
-
- def get_size(self, start_path="."):
- total_size = 0
- for dirpath, dirnames, filenames in os.walk(start_path):
- for f in filenames:
- fp = os.path.join(dirpath, f)
- total_size += os.path.getsize(fp)
- return total_size
+ self.count += 1
+ if self.max != 0:
+ percent = int(min(self.count * 100 / self.max, 100))
+ sys.stdout.write(f"\r[{percent:3d}%] ")
+ sys.stdout.flush()
+
+ from SCons.Script import Progress
+
+ progressor = ShowProgress()
+ Progress(progressor)
def progress_finish(target, source, env):
- nonlocal node_count, progressor
try:
- with open(node_count_fname, "w", encoding="utf-8", newline="\n") as f:
- f.write("%d\n" % node_count)
- except Exception:
+ with open(NODE_COUNT_FILENAME, "w", encoding="utf-8", newline="\n") as f:
+ f.write(f"{progressor.count}\n")
+ except OSError:
pass
- try:
- with open(node_count_fname, "r", encoding="utf-8") as f:
- node_count_max = int(f.readline())
- except Exception:
- pass
+ env.AlwaysBuild(
+ env.CommandNoCache(
+ "progress_finish", [], env.Action(progress_finish, "Building node count database .scons_node_count")
+ )
+ )
+
+
+def convert_size(size_bytes: int) -> str:
+ if size_bytes == 0:
+ return "0 bytes"
+ SIZE_NAMES = ["bytes", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"]
+ index = math.floor(math.log(size_bytes, 1024))
+ power = math.pow(1024, index)
+ size = round(size_bytes / power, 2)
+ return f"{size} {SIZE_NAMES[index]}"
- cache_directory = os.environ.get("SCONS_CACHE")
- # Simple cache pruning, attached to SCons' progress callback. Trim the
- # cache directory to a size not larger than cache_limit.
- cache_limit = float(os.getenv("SCONS_CACHE_LIMIT", 1024)) * 1024 * 1024
- progressor = cache_progress(cache_directory, cache_limit)
- Progress(progressor, interval=node_count_interval)
-
- progress_finish_command = Command("progress_finish", [], progress_finish)
- AlwaysBuild(progress_finish_command)
-
-
-def clean_cache(env):
- import atexit
- import time
-
- class cache_clean:
- def __init__(self, path=None, limit=pow(1024, 3)):
- self.path = path
- self.limit = limit
-
- def clean(self):
- self.delete(self.file_list())
-
- def delete(self, files):
- if len(files) == 0:
- return
- if env["verbose"]:
- # Utter something
- print("Purging %d %s from cache..." % (len(files), "files" if len(files) > 1 else "file"))
- [os.remove(f) for f in files]
-
- def file_list(self):
- if self.path is None:
- # Nothing to do
- return []
- # Gather a list of (filename, (size, atime)) within the
- # cache directory
- file_stat = [(x, os.stat(x)[6:8]) for x in glob.glob(os.path.join(self.path, "*", "*"))]
- if file_stat == []:
- # Nothing to do
- return []
- # Weight the cache files by size (assumed to be roughly
- # proportional to the recompilation time) times an exponential
- # decay since the ctime, and return a list with the entries
- # (filename, size, weight).
- current_time = time.time()
- file_stat = [(x[0], x[1][0], (current_time - x[1][1])) for x in file_stat]
- # Sort by the most recently accessed files (most sensible to keep) first
- file_stat.sort(key=lambda x: x[2])
- # Search for the first entry where the storage limit is
- # reached
- sum, mark = 0, None
- for i, x in enumerate(file_stat):
- sum += x[1]
- if sum > self.limit:
- mark = i
- break
- if mark is None:
- return []
- else:
- return [x[0] for x in file_stat[mark:]]
- def cache_finally():
- nonlocal cleaner
+def get_size(start_path: str = ".") -> int:
+ total_size = 0
+ for dirpath, _, filenames in os.walk(start_path):
+ for file in filenames:
+ path = os.path.join(dirpath, file)
+ total_size += os.path.getsize(path)
+ return total_size
+
+
+def clean_cache(cache_path: str, cache_limit: int, verbose: bool):
+ files = glob.glob(os.path.join(cache_path, "*", "*"))
+ if not files:
+ return
+
+ # Remove all text files, store binary files in list of (filename, size, atime).
+ purge = []
+ texts = []
+ stats = []
+ for file in files:
try:
- cleaner.clean()
- except Exception:
- pass
+ # Save file stats to rewrite after modifying.
+ tmp_stat = os.stat(file)
+ # Failing a utf-8 decode is the easiest way to determine if a file is binary.
+ try:
+ with open(file, encoding="utf-8") as out:
+ out.read(1024)
+ except UnicodeDecodeError:
+ stats.append((file, *tmp_stat[6:8]))
+ # Restore file stats after reading.
+ os.utime(file, (tmp_stat[7], tmp_stat[8]))
+ else:
+ texts.append(file)
+ except OSError:
+ print_error(f'Failed to access cache file "{file}"; skipping.')
- cache_directory = os.environ.get("SCONS_CACHE")
- # Simple cache pruning, attached to SCons' progress callback. Trim the
- # cache directory to a size not larger than cache_limit.
- cache_limit = float(os.getenv("SCONS_CACHE_LIMIT", 1024)) * 1024 * 1024
- cleaner = cache_clean(cache_directory, cache_limit)
+ if texts:
+ count = len(texts)
+ for file in texts:
+ try:
+ os.remove(file)
+ except OSError:
+ print_error(f'Failed to remove cache file "{file}"; skipping.')
+ count -= 1
+ if verbose:
+ print("Purging %d text %s from cache..." % (count, "files" if count > 1 else "file"))
+
+ if cache_limit:
+ # Sort by most recent access (most sensible to keep) first. Search for the first entry where
+ # the cache limit is reached.
+ stats.sort(key=lambda x: x[2], reverse=True)
+ sum = 0
+ for index, stat in enumerate(stats):
+ sum += stat[1]
+ if sum > cache_limit:
+ purge.extend([x[0] for x in stats[index:]])
+ break
+
+ if purge:
+ count = len(purge)
+ for file in purge:
+ try:
+ os.remove(file)
+ except OSError:
+ print_error(f'Failed to remove cache file "{file}"; skipping.')
+ count -= 1
+ if verbose:
+ print("Purging %d %s from cache..." % (count, "files" if count > 1 else "file"))
+
+
+def prepare_cache(env) -> None:
+ if env.GetOption("clean"):
+ return
- atexit.register(cache_finally)
+ cache_path = ""
+ if env["cache_path"]:
+ cache_path = cast(str, env["cache_path"])
+ elif os.environ.get("SCONS_CACHE"):
+ print_warning("Environment variable `SCONS_CACHE` is deprecated; use `cache_path` argument instead.")
+ cache_path = cast(str, os.environ.get("SCONS_CACHE"))
+
+ if not cache_path:
+ return
+
+ env.CacheDir(cache_path)
+ print(f'SCons cache enabled... (path: "{cache_path}")')
+
+ if env["cache_limit"]:
+ cache_limit = float(env["cache_limit"])
+ elif os.environ.get("SCONS_CACHE_LIMIT"):
+ print_warning("Environment variable `SCONS_CACHE_LIMIT` is deprecated; use `cache_limit` argument instead.")
+ cache_limit = float(os.getenv("SCONS_CACHE_LIMIT", "0")) / 1024 # Old method used MiB, convert to GiB
+
+ # Convert GiB to bytes; treat negative numbers as 0 (unlimited).
+ cache_limit = max(0, int(cache_limit * 1024 * 1024 * 1024))
+ if env["verbose"]:
+ print(
+ "Current cache limit is {} (used: {})".format(
+ convert_size(cache_limit) if cache_limit else "∞",
+ convert_size(get_size(cache_path)),
+ )
+ )
+
+ atexit.register(clean_cache, cache_path, cache_limit, env["verbose"])
def dump(env):
@@ -1025,6 +1018,30 @@ def generate_vs_project(env, original_args, project_name="godot"):
return v[0] if len(v) == 1 else f"{v[0]}={v[1]}"
return v
+ def get_dependencies(file, env, exts, headers, sources, others):
+ for child in file.children():
+ if isinstance(child, str):
+ child = env.File(x)
+ fname = ""
+ try:
+ fname = child.path
+ except AttributeError:
+ # It's not a file.
+ pass
+
+ if fname:
+ parts = os.path.splitext(fname)
+ if len(parts) > 1:
+ ext = parts[1].lower()
+ if ext in exts["sources"]:
+ sources += [fname]
+ elif ext in exts["headers"]:
+ headers += [fname]
+ elif ext in exts["others"]:
+ others += [fname]
+
+ get_dependencies(child, env, exts, headers, sources, others)
+
filtered_args = original_args.copy()
# Ignore the "vsproj" option to not regenerate the VS project on every build
@@ -1086,35 +1103,35 @@ def generate_vs_project(env, original_args, project_name="godot"):
sys.path.remove(tmppath)
sys.modules.pop("msvs")
+ extensions = {}
+ extensions["headers"] = [".h", ".hh", ".hpp", ".hxx", ".inc"]
+ extensions["sources"] = [".c", ".cc", ".cpp", ".cxx", ".m", ".mm", ".java"]
+ extensions["others"] = [".natvis", ".glsl", ".rc"]
+
headers = []
headers_dirs = []
- for file in glob_recursive_2("*.h", headers_dirs):
- headers.append(str(file).replace("/", "\\"))
- for file in glob_recursive_2("*.hpp", headers_dirs):
- headers.append(str(file).replace("/", "\\"))
+ for ext in extensions["headers"]:
+ for file in glob_recursive_2("*" + ext, headers_dirs):
+ headers.append(str(file).replace("/", "\\"))
sources = []
sources_dirs = []
- for file in glob_recursive_2("*.cpp", sources_dirs):
- sources.append(str(file).replace("/", "\\"))
- for file in glob_recursive_2("*.c", sources_dirs):
- sources.append(str(file).replace("/", "\\"))
+ for ext in extensions["sources"]:
+ for file in glob_recursive_2("*" + ext, sources_dirs):
+ sources.append(str(file).replace("/", "\\"))
others = []
others_dirs = []
- for file in glob_recursive_2("*.natvis", others_dirs):
- others.append(str(file).replace("/", "\\"))
- for file in glob_recursive_2("*.glsl", others_dirs):
- others.append(str(file).replace("/", "\\"))
+ for ext in extensions["others"]:
+ for file in glob_recursive_2("*" + ext, others_dirs):
+ others.append(str(file).replace("/", "\\"))
skip_filters = False
import hashlib
import json
md5 = hashlib.md5(
- json.dumps(headers + headers_dirs + sources + sources_dirs + others + others_dirs, sort_keys=True).encode(
- "utf-8"
- )
+ json.dumps(sorted(headers + headers_dirs + sources + sources_dirs + others + others_dirs)).encode("utf-8")
).hexdigest()
if os.path.exists(f"{project_name}.vcxproj.filters"):
@@ -1171,58 +1188,13 @@ def generate_vs_project(env, original_args, project_name="godot"):
with open(f"{project_name}.vcxproj.filters", "w", encoding="utf-8", newline="\r\n") as f:
f.write(filters_template)
- envsources = []
-
- envsources += env.core_sources
- envsources += env.drivers_sources
- envsources += env.main_sources
- envsources += env.modules_sources
- envsources += env.scene_sources
- envsources += env.servers_sources
- if env.editor_build:
- envsources += env.editor_sources
- envsources += env.platform_sources
-
headers_active = []
sources_active = []
others_active = []
- for x in envsources:
- fname = ""
- if isinstance(x, str):
- fname = env.File(x).path
- else:
- # Some object files might get added directly as a File object and not a list.
- try:
- fname = env.File(x)[0].path
- except Exception:
- fname = x.path
- pass
- if fname:
- fname = fname.replace("\\\\", "/")
- parts = os.path.splitext(fname)
- basename = parts[0]
- ext = parts[1]
- idx = fname.find(env["OBJSUFFIX"])
- if ext in [".h", ".hpp"]:
- headers_active += [fname]
- elif ext in [".c", ".cpp"]:
- sources_active += [fname]
- elif idx > 0:
- basename = fname[:idx]
- if os.path.isfile(basename + ".h"):
- headers_active += [basename + ".h"]
- elif os.path.isfile(basename + ".hpp"):
- headers_active += [basename + ".hpp"]
- elif basename.endswith(".gen") and os.path.isfile(basename[:-4] + ".h"):
- headers_active += [basename[:-4] + ".h"]
- if os.path.isfile(basename + ".c"):
- sources_active += [basename + ".c"]
- elif os.path.isfile(basename + ".cpp"):
- sources_active += [basename + ".cpp"]
- else:
- fname = os.path.relpath(os.path.abspath(fname), env.Dir("").abspath)
- others_active += [fname]
+ get_dependencies(
+ env.File(f"#bin/godot{env['PROGSUFFIX']}"), env, extensions, headers_active, sources_active, others_active
+ )
all_items = []
properties = []
diff --git a/misc/dist/html/editor.html b/misc/dist/html/editor.html
index 3a22055546..4f2a3bc053 100644
--- a/misc/dist/html/editor.html
+++ b/misc/dist/html/editor.html
@@ -363,24 +363,28 @@ window.addEventListener('load', () => {
btn.style.display = '';
}
if ('serviceWorker' in navigator) {
- navigator.serviceWorker.register('service.worker.js').then(function (reg) {
- if (reg.waiting) {
- notifyUpdate(reg.waiting);
- }
- reg.addEventListener('updatefound', function () {
- const update = reg.installing;
- update.addEventListener('statechange', function () {
- if (update.state === 'installed') {
- // It's a new install, claim and perform aggressive caching.
- if (!reg.active) {
- update.postMessage('claim');
- } else {
- notifyUpdate(update);
+ try {
+ navigator.serviceWorker.register('service.worker.js').then(function (reg) {
+ if (reg.waiting) {
+ notifyUpdate(reg.waiting);
+ }
+ reg.addEventListener('updatefound', function () {
+ const update = reg.installing;
+ update.addEventListener('statechange', function () {
+ if (update.state === 'installed') {
+ // It's a new install, claim and perform aggressive caching.
+ if (!reg.active) {
+ update.postMessage('claim');
+ } else {
+ notifyUpdate(update);
+ }
}
- }
+ });
});
});
- });
+ } catch (e) {
+ console.error('Error while registering service worker:', e);
+ }
}
const missing = Engine.getMissingFeatures({
diff --git a/misc/dist/html/full-size.html b/misc/dist/html/full-size.html
index 352046df30..3d68b66f49 100644
--- a/misc/dist/html/full-size.html
+++ b/misc/dist/html/full-size.html
@@ -38,7 +38,7 @@ body {
}
#status {
- background-color: #242424;
+ background-color: $GODOT_SPLASH_COLOR;
display: flex;
flex-direction: column;
justify-content: center;
@@ -152,9 +152,15 @@ const engine = new Engine(GODOT_CONFIG);
if (missing.length !== 0) {
if (GODOT_CONFIG['serviceWorker'] && GODOT_CONFIG['ensureCrossOriginIsolationHeaders'] && 'serviceWorker' in navigator) {
+ let serviceWorkerRegistrationPromise;
+ try {
+ serviceWorkerRegistrationPromise = navigator.serviceWorker.getRegistration();
+ } catch (err) {
+ serviceWorkerRegistrationPromise = Promise.reject(new Error('Service worker registration failed.'));
+ }
// There's a chance that installing the service worker would fix the issue
Promise.race([
- navigator.serviceWorker.getRegistration().then((registration) => {
+ serviceWorkerRegistrationPromise.then((registration) => {
if (registration != null) {
return Promise.reject(new Error('Service worker already exists.'));
}
diff --git a/misc/extension_api_validation/4.3-stable.expected b/misc/extension_api_validation/4.3-stable.expected
index 3770664115..506844e6d6 100644
--- a/misc/extension_api_validation/4.3-stable.expected
+++ b/misc/extension_api_validation/4.3-stable.expected
@@ -108,3 +108,54 @@ GH-97257
Validate extension JSON: Error: Field 'classes/EditorFeatureProfile/enums/Feature/values/FEATURE_MAX': value changed value in new API, from 8.0 to 9.
New entry to the `EditorFeatureProfile.Feature` enum added. Those need to go before `FEATURE_MAX`, which will always cause a compatibility break.
+
+
+GH-91201
+--------
+Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/OS/methods/read_string_from_stdin': arguments
+
+Added optional argument. Compatibility method registered.
+
+
+GH-98918
+--------
+Validate extension JSON: Error: Field 'classes/FileAccess/methods/open_encrypted/arguments': size changed value in new API, from 3 to 4.
+
+Optional argument added to allow setting initialization vector. Compatibility method registered.
+
+
+GH-98972
+--------
+Validate extension JSON: Error: Field 'classes/TranslationServer/methods/standardize_locale/arguments': size changed value in new API, from 1 to 2.
+
+Optional argument added. Compatibility method registered.
+
+
+GH-99424
+--------
+Validate extension JSON: API was removed: builtin_classes/Projection/constants/PLANE_BOTTOM
+Validate extension JSON: API was removed: builtin_classes/Projection/constants/PLANE_FAR
+Validate extension JSON: API was removed: builtin_classes/Projection/constants/PLANE_LEFT
+Validate extension JSON: API was removed: builtin_classes/Projection/constants/PLANE_NEAR
+Validate extension JSON: API was removed: builtin_classes/Projection/constants/PLANE_RIGHT
+Validate extension JSON: API was removed: builtin_classes/Projection/constants/PLANE_TOP
+Validate extension JSON: API was removed: builtin_classes/Vector2/constants/AXIS_X
+Validate extension JSON: API was removed: builtin_classes/Vector2/constants/AXIS_Y
+Validate extension JSON: API was removed: builtin_classes/Vector2i/constants/AXIS_X
+Validate extension JSON: API was removed: builtin_classes/Vector2i/constants/AXIS_Y
+Validate extension JSON: API was removed: builtin_classes/Vector3/constants/AXIS_X
+Validate extension JSON: API was removed: builtin_classes/Vector3/constants/AXIS_Y
+Validate extension JSON: API was removed: builtin_classes/Vector3/constants/AXIS_Z
+Validate extension JSON: API was removed: builtin_classes/Vector3i/constants/AXIS_X
+Validate extension JSON: API was removed: builtin_classes/Vector3i/constants/AXIS_Y
+Validate extension JSON: API was removed: builtin_classes/Vector3i/constants/AXIS_Z
+Validate extension JSON: API was removed: builtin_classes/Vector4/constants/AXIS_W
+Validate extension JSON: API was removed: builtin_classes/Vector4/constants/AXIS_X
+Validate extension JSON: API was removed: builtin_classes/Vector4/constants/AXIS_Y
+Validate extension JSON: API was removed: builtin_classes/Vector4/constants/AXIS_Z
+Validate extension JSON: API was removed: builtin_classes/Vector4i/constants/AXIS_W
+Validate extension JSON: API was removed: builtin_classes/Vector4i/constants/AXIS_X
+Validate extension JSON: API was removed: builtin_classes/Vector4i/constants/AXIS_Y
+Validate extension JSON: API was removed: builtin_classes/Vector4i/constants/AXIS_Z
+
+These constants have been replaced with corresponding enum constants.
diff --git a/misc/utility/.clang-format-glsl b/misc/utility/.clang-format-glsl
index 59efa8fa35..c588df0236 100644
--- a/misc/utility/.clang-format-glsl
+++ b/misc/utility/.clang-format-glsl
@@ -30,7 +30,10 @@ JavaImportGroups:
- com.google
- java
- javax
-KeepEmptyLinesAtTheStartOfBlocks: false
+KeepEmptyLines:
+ AtEndOfFile: false
+ AtStartOfBlock: false
+ AtStartOfFile: false
ObjCBlockIndentWidth: 4
PackConstructorInitializers: NextLine
RemoveSemicolon: false # Differs from base .clang-format
diff --git a/modules/SCsub b/modules/SCsub
index fea2f2eeb8..09944241ea 100644
--- a/modules/SCsub
+++ b/modules/SCsub
@@ -63,7 +63,6 @@ register_module_types = env.CommandNoCache(
)
-vs_sources = []
test_headers = []
# libmodule_<name>.a for each active module.
for name, path in env.module_list.items():
@@ -75,8 +74,6 @@ for name, path in env.module_list.items():
lib = env_modules.add_library("module_%s" % name, env.modules_sources)
env.Prepend(LIBS=[lib])
- if env["vsproj"]:
- vs_sources += env.modules_sources
if env["tests"]:
# Lookup potential headers in `tests` subfolder.
@@ -104,5 +101,3 @@ env.modules_sources = []
env_modules.add_source_files(env.modules_sources, register_module_types)
lib = env_modules.add_library("modules", env.modules_sources)
env.Prepend(LIBS=[lib])
-if env["vsproj"]:
- env.modules_sources += vs_sources
diff --git a/modules/basis_universal/image_compress_basisu.cpp b/modules/basis_universal/image_compress_basisu.cpp
index 8ca5dba225..be28d89508 100644
--- a/modules/basis_universal/image_compress_basisu.cpp
+++ b/modules/basis_universal/image_compress_basisu.cpp
@@ -38,13 +38,12 @@
#include <transcoder/basisu_transcoder.h>
#ifdef TOOLS_ENABLED
#include <encoder/basisu_comp.h>
-#endif
-void basis_universal_init() {
-#ifdef TOOLS_ENABLED
- basisu::basisu_encoder_init();
+static Mutex init_mutex;
+static bool initialized = false;
#endif
+void basis_universal_init() {
basist::basisu_transcoder_init();
}
@@ -80,6 +79,13 @@ inline void _basisu_pad_mipmap(const uint8_t *p_image_mip_data, Vector<uint8_t>
}
Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedChannels p_channels) {
+ init_mutex.lock();
+ if (!initialized) {
+ basisu::basisu_encoder_init();
+ initialized = true;
+ }
+ init_mutex.unlock();
+
uint64_t start_time = OS::get_singleton()->get_ticks_msec();
Ref<Image> image = p_image->duplicate();
diff --git a/modules/betsy/CrossPlatformSettings_piece_all.glsl b/modules/betsy/CrossPlatformSettings_piece_all.glsl
index b7abac7fcc..001d8e63b2 100644
--- a/modules/betsy/CrossPlatformSettings_piece_all.glsl
+++ b/modules/betsy/CrossPlatformSettings_piece_all.glsl
@@ -1,4 +1,3 @@
-
#define min3(a, b, c) min(a, min(b, c))
#define max3(a, b, c) max(a, max(b, c))
diff --git a/modules/betsy/UavCrossPlatform_piece_all.glsl b/modules/betsy/UavCrossPlatform_piece_all.glsl
index 30854df637..5f074137af 100644
--- a/modules/betsy/UavCrossPlatform_piece_all.glsl
+++ b/modules/betsy/UavCrossPlatform_piece_all.glsl
@@ -1,4 +1,3 @@
-
#define OGRE_imageLoad2D(inImage, iuv) imageLoad(inImage, int2(iuv))
#define OGRE_imageLoad2DArray(inImage, iuvw) imageLoad(inImage, int3(iuvw))
diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp
index 601d0e0c24..667de70d13 100644
--- a/modules/dds/texture_loader_dds.cpp
+++ b/modules/dds/texture_loader_dds.cpp
@@ -289,6 +289,15 @@ static Ref<Image> _dds_load_layer(Ref<FileAccess> p_file, DDSFormat p_dds_format
if (info.compressed) {
// BC compressed.
+ w += w % info.divisor;
+ h += h % info.divisor;
+ if (w != p_width) {
+ WARN_PRINT(vformat("%s: DDS width '%d' is not divisible by %d. This is not allowed as per the DDS specification, attempting to load anyway.", p_file->get_path(), p_width, info.divisor));
+ }
+ if (h != p_height) {
+ WARN_PRINT(vformat("%s: DDS height '%d' is not divisible by %d. This is not allowed as per the DDS specification, attempting to load anyway.", p_file->get_path(), p_height, info.divisor));
+ }
+
uint32_t size = MAX(info.divisor, w) / info.divisor * MAX(info.divisor, h) / info.divisor * info.block_size;
if (p_flags & DDSD_LINEARSIZE) {
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index ede4ce6617..0355119442 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -666,7 +666,19 @@
@export var car_label = "Speedy"
@export var car_number = 3
[/codeblock]
- [b]Note:[/b] Subgroups cannot be nested, they only provide one extra level of depth. Just like the next group ends the previous group, so do the subsequent subgroups.
+ [b]Note:[/b] Subgroups cannot be nested, but you can use the slash separator ([code]/[/code]) to achieve the desired effect:
+ [codeblock]
+ @export_group("Car Properties")
+ @export_subgroup("Wheels", "wheel_")
+ @export_subgroup("Wheels/Front", "front_wheel_")
+ @export var front_wheel_strength = 10
+ @export var front_wheel_mobility = 5
+ @export_subgroup("Wheels/Rear", "rear_wheel_")
+ @export var rear_wheel_strength = 8
+ @export var rear_wheel_mobility = 3
+ @export_subgroup("Wheels", "wheel_")
+ @export var wheel_material: PhysicsMaterial
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_tool_button">
diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml
index 5f7a7e2915..c3fa59dc23 100644
--- a/modules/gdscript/doc_classes/GDScript.xml
+++ b/modules/gdscript/doc_classes/GDScript.xml
@@ -16,11 +16,10 @@
<return type="Variant" />
<description>
Returns a new instance of the script.
- For example:
[codeblock]
var MyClass = load("myclass.gd")
var instance = MyClass.new()
- assert(instance.get_script() == MyClass)
+ print(instance.get_script() == MyClass) # Prints true
[/codeblock]
</description>
</method>
diff --git a/modules/gdscript/editor/gdscript_docgen.cpp b/modules/gdscript/editor/gdscript_docgen.cpp
index 758887a723..3a5a88d356 100644
--- a/modules/gdscript/editor/gdscript_docgen.cpp
+++ b/modules/gdscript/editor/gdscript_docgen.cpp
@@ -140,7 +140,7 @@ void GDScriptDocGen::_doctype_from_gdtype(const GDType &p_gdtype, String &r_type
r_enum = String(p_gdtype.native_type).replace("::", ".");
if (r_enum.begins_with("res://")) {
r_enum = r_enum.trim_prefix("res://");
- int dot_pos = r_enum.rfind(".");
+ int dot_pos = r_enum.rfind_char('.');
if (dot_pos >= 0) {
r_enum = r_enum.left(dot_pos).quote() + r_enum.substr(dot_pos);
}
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index 0b12f2ff76..629581bd6c 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -163,7 +163,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
}
if (from + end_key_length > line_length) {
// If it's key length and there is a '\', dont skip to highlight esc chars.
- if (str.find("\\", from) >= 0) {
+ if (str.find_char('\\', from) >= 0) {
break;
}
}
@@ -236,7 +236,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
for (; from < line_length; from++) {
if (line_length - from < end_key_length) {
// Don't break if '\' to highlight esc chars.
- if (str.find("\\", from) < 0) {
+ if (str.find_char('\\', from) < 0) {
break;
}
}
diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
index b31ae878ce..172ad6be9f 100644
--- a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
+++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
@@ -51,6 +51,10 @@ Error GDScriptEditorTranslationParserPlugin::parse_file(const String &p_path, Ve
ids = r_ids;
ids_ctx_plural = r_ids_ctx_plural;
+
+ ids_comment.clear();
+ ids_ctx_plural_comment.clear();
+
Ref<GDScript> gdscript = loaded_res;
String source_code = gdscript->get_source_code();
@@ -62,18 +66,90 @@ Error GDScriptEditorTranslationParserPlugin::parse_file(const String &p_path, Ve
err = analyzer.analyze();
ERR_FAIL_COND_V_MSG(err, err, "Failed to analyze GDScript with GDScriptAnalyzer.");
+ comment_data = &parser.comment_data;
+
// Traverse through the parsed tree from GDScriptParser.
GDScriptParser::ClassNode *c = parser.get_tree();
_traverse_class(c);
+ comment_data = nullptr;
+
return OK;
}
+void GDScriptEditorTranslationParserPlugin::get_comments(Vector<String> *r_ids_comment, Vector<String> *r_ids_ctx_plural_comment) {
+ r_ids_comment->append_array(ids_comment);
+ r_ids_ctx_plural_comment->append_array(ids_ctx_plural_comment);
+}
+
bool GDScriptEditorTranslationParserPlugin::_is_constant_string(const GDScriptParser::ExpressionNode *p_expression) {
ERR_FAIL_NULL_V(p_expression, false);
return p_expression->is_constant && p_expression->reduced_value.is_string();
}
+String GDScriptEditorTranslationParserPlugin::_parse_comment(int p_line, bool &r_skip) const {
+ // Parse inline comment.
+ if (comment_data->has(p_line)) {
+ const String stripped_comment = comment_data->get(p_line).comment.trim_prefix("#").strip_edges();
+
+ if (stripped_comment.begins_with("TRANSLATORS:")) {
+ return stripped_comment.trim_prefix("TRANSLATORS:").strip_edges(true, false);
+ }
+ if (stripped_comment == "NO_TRANSLATE" || stripped_comment.begins_with("NO_TRANSLATE:")) {
+ r_skip = true;
+ return String();
+ }
+ }
+
+ // Parse multiline comment.
+ String multiline_comment;
+ for (int line = p_line - 1; comment_data->has(line) && comment_data->get(line).new_line; line--) {
+ const String stripped_comment = comment_data->get(line).comment.trim_prefix("#").strip_edges();
+
+ if (stripped_comment.is_empty()) {
+ continue;
+ }
+
+ if (multiline_comment.is_empty()) {
+ multiline_comment = stripped_comment;
+ } else {
+ multiline_comment = stripped_comment + "\n" + multiline_comment;
+ }
+
+ if (stripped_comment.begins_with("TRANSLATORS:")) {
+ return multiline_comment.trim_prefix("TRANSLATORS:").strip_edges(true, false);
+ }
+ if (stripped_comment == "NO_TRANSLATE" || stripped_comment.begins_with("NO_TRANSLATE:")) {
+ r_skip = true;
+ return String();
+ }
+ }
+
+ return String();
+}
+
+void GDScriptEditorTranslationParserPlugin::_add_id(const String &p_id, int p_line) {
+ bool skip = false;
+ const String comment = _parse_comment(p_line, skip);
+ if (skip) {
+ return;
+ }
+
+ ids->push_back(p_id);
+ ids_comment.push_back(comment);
+}
+
+void GDScriptEditorTranslationParserPlugin::_add_id_ctx_plural(const Vector<String> &p_id_ctx_plural, int p_line) {
+ bool skip = false;
+ const String comment = _parse_comment(p_line, skip);
+ if (skip) {
+ return;
+ }
+
+ ids_ctx_plural->push_back(p_id_ctx_plural);
+ ids_ctx_plural_comment.push_back(comment);
+}
+
void GDScriptEditorTranslationParserPlugin::_traverse_class(const GDScriptParser::ClassNode *p_class) {
for (int i = 0; i < p_class->members.size(); i++) {
const GDScriptParser::ClassNode::Member &m = p_class->members[i];
@@ -253,7 +329,7 @@ void GDScriptEditorTranslationParserPlugin::_assess_assignment(const GDScriptPar
if (assignee_name != StringName() && assignment_patterns.has(assignee_name) && _is_constant_string(p_assignment->assigned_value)) {
// If the assignment is towards one of the extract patterns (text, tooltip_text etc.), and the value is a constant string, we collect the string.
- ids->push_back(p_assignment->assigned_value->reduced_value);
+ _add_id(p_assignment->assigned_value->reduced_value, p_assignment->assigned_value->start_line);
} else if (assignee_name == fd_filters) {
// Extract from `get_node("FileDialog").filters = <filter array>`.
_extract_fd_filter_array(p_assignment->assigned_value);
@@ -287,7 +363,7 @@ void GDScriptEditorTranslationParserPlugin::_assess_call(const GDScriptParser::C
}
}
if (extract_id_ctx_plural) {
- ids_ctx_plural->push_back(id_ctx_plural);
+ _add_id_ctx_plural(id_ctx_plural, p_call->start_line);
}
} else if (function_name == trn_func || function_name == atrn_func) {
// Extract from `tr_n(id, plural, n, ctx)` or `atr_n(id, plural, n, ctx)`.
@@ -307,20 +383,20 @@ void GDScriptEditorTranslationParserPlugin::_assess_call(const GDScriptParser::C
}
}
if (extract_id_ctx_plural) {
- ids_ctx_plural->push_back(id_ctx_plural);
+ _add_id_ctx_plural(id_ctx_plural, p_call->start_line);
}
} else if (first_arg_patterns.has(function_name)) {
if (!p_call->arguments.is_empty() && _is_constant_string(p_call->arguments[0])) {
- ids->push_back(p_call->arguments[0]->reduced_value);
+ _add_id(p_call->arguments[0]->reduced_value, p_call->arguments[0]->start_line);
}
} else if (second_arg_patterns.has(function_name)) {
if (p_call->arguments.size() > 1 && _is_constant_string(p_call->arguments[1])) {
- ids->push_back(p_call->arguments[1]->reduced_value);
+ _add_id(p_call->arguments[1]->reduced_value, p_call->arguments[1]->start_line);
}
} else if (function_name == fd_add_filter) {
// Extract the 'JPE Images' in this example - get_node("FileDialog").add_filter("*.jpg; JPE Images").
if (!p_call->arguments.is_empty()) {
- _extract_fd_filter_string(p_call->arguments[0]);
+ _extract_fd_filter_string(p_call->arguments[0], p_call->arguments[0]->start_line);
}
} else if (function_name == fd_set_filter) {
// Extract from `get_node("FileDialog").set_filters(<filter array>)`.
@@ -330,12 +406,12 @@ void GDScriptEditorTranslationParserPlugin::_assess_call(const GDScriptParser::C
}
}
-void GDScriptEditorTranslationParserPlugin::_extract_fd_filter_string(const GDScriptParser::ExpressionNode *p_expression) {
+void GDScriptEditorTranslationParserPlugin::_extract_fd_filter_string(const GDScriptParser::ExpressionNode *p_expression, int p_line) {
// Extract the name in "extension ; name".
if (_is_constant_string(p_expression)) {
PackedStringArray arr = p_expression->reduced_value.operator String().split(";", true);
ERR_FAIL_COND_MSG(arr.size() != 2, "Argument for setting FileDialog has bad format.");
- ids->push_back(arr[1].strip_edges());
+ _add_id(arr[1].strip_edges(), p_line);
}
}
@@ -355,7 +431,7 @@ void GDScriptEditorTranslationParserPlugin::_extract_fd_filter_array(const GDScr
if (array_node) {
for (int i = 0; i < array_node->elements.size(); i++) {
- _extract_fd_filter_string(array_node->elements[i]);
+ _extract_fd_filter_string(array_node->elements[i], array_node->elements[i]->start_line);
}
}
}
diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.h b/modules/gdscript/editor/gdscript_translation_parser_plugin.h
index 61ff81ed66..73e8f53110 100644
--- a/modules/gdscript/editor/gdscript_translation_parser_plugin.h
+++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.h
@@ -32,16 +32,23 @@
#define GDSCRIPT_TRANSLATION_PARSER_PLUGIN_H
#include "../gdscript_parser.h"
+#include "../gdscript_tokenizer.h"
+#include "core/templates/hash_map.h"
#include "core/templates/hash_set.h"
#include "editor/editor_translation_parser.h"
class GDScriptEditorTranslationParserPlugin : public EditorTranslationParserPlugin {
GDCLASS(GDScriptEditorTranslationParserPlugin, EditorTranslationParserPlugin);
+ const HashMap<int, GDScriptTokenizer::CommentData> *comment_data = nullptr;
+
Vector<String> *ids = nullptr;
Vector<Vector<String>> *ids_ctx_plural = nullptr;
+ Vector<String> ids_comment;
+ Vector<String> ids_ctx_plural_comment;
+
// List of patterns used for extracting translation strings.
StringName tr_func = "tr";
StringName trn_func = "tr_n";
@@ -57,6 +64,11 @@ class GDScriptEditorTranslationParserPlugin : public EditorTranslationParserPlug
static bool _is_constant_string(const GDScriptParser::ExpressionNode *p_expression);
+ String _parse_comment(int p_line, bool &r_skip) const;
+
+ void _add_id(const String &p_id, int p_line);
+ void _add_id_ctx_plural(const Vector<String> &p_id_ctx_plural, int p_line);
+
void _traverse_class(const GDScriptParser::ClassNode *p_class);
void _traverse_function(const GDScriptParser::FunctionNode *p_func);
void _traverse_block(const GDScriptParser::SuiteNode *p_suite);
@@ -65,11 +77,12 @@ class GDScriptEditorTranslationParserPlugin : public EditorTranslationParserPlug
void _assess_assignment(const GDScriptParser::AssignmentNode *p_assignment);
void _assess_call(const GDScriptParser::CallNode *p_call);
- void _extract_fd_filter_string(const GDScriptParser::ExpressionNode *p_expression);
+ void _extract_fd_filter_string(const GDScriptParser::ExpressionNode *p_expression, int p_line);
void _extract_fd_filter_array(const GDScriptParser::ExpressionNode *p_expression);
public:
virtual Error parse_file(const String &p_path, Vector<String> *r_ids, Vector<Vector<String>> *r_ids_ctx_plural) override;
+ virtual void get_comments(Vector<String> *r_ids_comment, Vector<String> *r_ids_ctx_plural_comment) override;
virtual void get_recognized_extensions(List<String> *r_extensions) const override;
GDScriptEditorTranslationParserPlugin();
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 6241ada06a..af92450835 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -169,7 +169,9 @@ static GDScriptParser::DataType make_native_enum_type(const StringName &p_enum_n
GDScriptParser::DataType type = make_enum_type(p_enum_name, native_base, p_meta);
if (p_meta) {
- type.builtin_type = Variant::NIL; // Native enum types are not Dictionaries.
+ // Native enum types are not dictionaries.
+ type.builtin_type = Variant::NIL;
+ type.is_pseudo_type = true;
}
List<StringName> enum_values;
@@ -182,10 +184,29 @@ static GDScriptParser::DataType make_native_enum_type(const StringName &p_enum_n
return type;
}
+static GDScriptParser::DataType make_builtin_enum_type(const StringName &p_enum_name, Variant::Type p_type, bool p_meta = true) {
+ GDScriptParser::DataType type = make_enum_type(p_enum_name, Variant::get_type_name(p_type), p_meta);
+ if (p_meta) {
+ // Built-in enum types are not dictionaries.
+ type.builtin_type = Variant::NIL;
+ type.is_pseudo_type = true;
+ }
+
+ List<StringName> enum_values;
+ Variant::get_enumerations_for_enum(p_type, p_enum_name, &enum_values);
+
+ for (const StringName &E : enum_values) {
+ type.enum_values[E] = Variant::get_enum_value(p_type, p_enum_name, E);
+ }
+
+ return type;
+}
+
static GDScriptParser::DataType make_global_enum_type(const StringName &p_enum_name, const StringName &p_base, bool p_meta = true) {
GDScriptParser::DataType type = make_enum_type(p_enum_name, p_base, p_meta);
if (p_meta) {
- type.builtin_type = Variant::NIL; // Native enum types are not Dictionaries.
+ // Global enum types are not dictionaries.
+ type.builtin_type = Variant::NIL;
type.is_pseudo_type = true;
}
@@ -703,8 +724,8 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
if (first == SNAME("Variant")) {
if (p_type->type_chain.size() == 2) {
// May be nested enum.
- StringName enum_name = p_type->type_chain[1]->name;
- StringName qualified_name = String(first) + ENUM_SEPARATOR + String(p_type->type_chain[1]->name);
+ const StringName enum_name = p_type->type_chain[1]->name;
+ const StringName qualified_name = String(first) + ENUM_SEPARATOR + String(p_type->type_chain[1]->name);
if (CoreConstants::is_global_enum(qualified_name)) {
result = make_global_enum_type(enum_name, first, true);
return result;
@@ -719,21 +740,34 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
result.kind = GDScriptParser::DataType::VARIANT;
} else if (GDScriptParser::get_builtin_type(first) < Variant::VARIANT_MAX) {
// Built-in types.
- if (p_type->type_chain.size() > 1) {
- push_error(R"(Built-in types don't contain nested types.)", p_type->type_chain[1]);
+ const Variant::Type builtin_type = GDScriptParser::get_builtin_type(first);
+
+ if (p_type->type_chain.size() == 2) {
+ // May be nested enum.
+ const StringName enum_name = p_type->type_chain[1]->name;
+ if (Variant::has_enum(builtin_type, enum_name)) {
+ result = make_builtin_enum_type(enum_name, builtin_type, true);
+ return result;
+ } else {
+ push_error(vformat(R"(Name "%s" is not a nested type of "%s".)", enum_name, first), p_type->type_chain[1]);
+ return bad_type;
+ }
+ } else if (p_type->type_chain.size() > 2) {
+ push_error(R"(Built-in types only contain enum types, which do not have nested types.)", p_type->type_chain[2]);
return bad_type;
}
+
result.kind = GDScriptParser::DataType::BUILTIN;
- result.builtin_type = GDScriptParser::get_builtin_type(first);
+ result.builtin_type = builtin_type;
- if (result.builtin_type == Variant::ARRAY) {
+ if (builtin_type == Variant::ARRAY) {
GDScriptParser::DataType container_type = type_from_metatype(resolve_datatype(p_type->get_container_type_or_null(0)));
if (container_type.kind != GDScriptParser::DataType::VARIANT) {
container_type.is_constant = false;
result.set_container_element_type(0, container_type);
}
}
- if (result.builtin_type == Variant::DICTIONARY) {
+ if (builtin_type == Variant::DICTIONARY) {
GDScriptParser::DataType key_type = type_from_metatype(resolve_datatype(p_type->get_container_type_or_null(0)));
if (key_type.kind != GDScriptParser::DataType::VARIANT) {
key_type.is_constant = false;
@@ -3970,13 +4004,36 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
if (base.kind == GDScriptParser::DataType::BUILTIN) {
if (base.is_meta_type) {
- bool valid = true;
- Variant result = Variant::get_constant_value(base.builtin_type, name, &valid);
- if (valid) {
+ bool valid = false;
+
+ if (Variant::has_constant(base.builtin_type, name)) {
+ valid = true;
+
+ const Variant constant_value = Variant::get_constant_value(base.builtin_type, name);
+
p_identifier->is_constant = true;
- p_identifier->reduced_value = result;
- p_identifier->set_datatype(type_from_variant(result, p_identifier));
- } else if (base.is_hard_type()) {
+ p_identifier->reduced_value = constant_value;
+ p_identifier->set_datatype(type_from_variant(constant_value, p_identifier));
+ }
+
+ if (!valid) {
+ const StringName enum_name = Variant::get_enum_for_enumeration(base.builtin_type, name);
+ if (enum_name != StringName()) {
+ valid = true;
+
+ p_identifier->is_constant = true;
+ p_identifier->reduced_value = Variant::get_enum_value(base.builtin_type, enum_name, name);
+ p_identifier->set_datatype(make_builtin_enum_type(enum_name, base.builtin_type, false));
+ }
+ }
+
+ if (!valid && Variant::has_enum(base.builtin_type, name)) {
+ valid = true;
+
+ p_identifier->set_datatype(make_builtin_enum_type(name, base.builtin_type, true));
+ }
+
+ if (!valid && base.is_hard_type()) {
#ifdef SUGGEST_GODOT4_RENAMES
String rename_hint;
if (GLOBAL_GET(GDScriptWarning::get_settings_path_from_code(GDScriptWarning::RENAMED_IN_GODOT_4_HINT)).booleanize()) {
@@ -3985,9 +4042,9 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
rename_hint = " " + vformat(R"(Did you mean to use "%s"?)", renamed_identifier_name);
}
}
- push_error(vformat(R"(Cannot find constant "%s" on base "%s".%s)", name, base.to_string(), rename_hint), p_identifier);
+ push_error(vformat(R"(Cannot find member "%s" in base "%s".%s)", name, base.to_string(), rename_hint), p_identifier);
#else
- push_error(vformat(R"(Cannot find constant "%s" on base "%s".)", name, base.to_string()), p_identifier);
+ push_error(vformat(R"(Cannot find member "%s" in base "%s".)", name, base.to_string()), p_identifier);
#endif // SUGGEST_GODOT4_RENAMES
}
} else {
@@ -4029,9 +4086,9 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
rename_hint = " " + vformat(R"(Did you mean to use "%s"?)", renamed_identifier_name);
}
}
- push_error(vformat(R"(Cannot find property "%s" on base "%s".%s)", name, base.to_string(), rename_hint), p_identifier);
+ push_error(vformat(R"(Cannot find member "%s" in base "%s".%s)", name, base.to_string(), rename_hint), p_identifier);
#else
- push_error(vformat(R"(Cannot find property "%s" on base "%s".)", name, base.to_string()), p_identifier);
+ push_error(vformat(R"(Cannot find member "%s" in base "%s".)", name, base.to_string()), p_identifier);
#endif // SUGGEST_GODOT4_RENAMES
}
}
@@ -5572,7 +5629,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo
} else {
Vector<String> names = String(p_property.class_name).split(ENUM_SEPARATOR);
if (names.size() == 2) {
- result = make_native_enum_type(names[1], names[0], false);
+ result = make_enum_type(names[1], names[0], false);
result.is_constant = false;
}
}
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index b77c641eb5..fb4d27caab 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -585,8 +585,25 @@ void GDScriptByteCodeGenerator::write_unary_operator(const Address &p_target, Va
}
void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) {
- // Avoid validated evaluator for modulo and division when operands are int, since there's no check for division by zero.
- if (HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand) && ((p_operator != Variant::OP_DIVIDE && p_operator != Variant::OP_MODULE) || p_left_operand.type.builtin_type != Variant::INT || p_right_operand.type.builtin_type != Variant::INT)) {
+ bool valid = HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand);
+
+ // Avoid validated evaluator for modulo and division when operands are int or integer vector, since there's no check for division by zero.
+ if (valid && (p_operator == Variant::OP_DIVIDE || p_operator == Variant::OP_MODULE)) {
+ switch (p_left_operand.type.builtin_type) {
+ case Variant::INT:
+ valid = p_right_operand.type.builtin_type != Variant::INT;
+ break;
+ case Variant::VECTOR2I:
+ case Variant::VECTOR3I:
+ case Variant::VECTOR4I:
+ valid = p_right_operand.type.builtin_type != Variant::INT && p_right_operand.type.builtin_type != p_left_operand.type.builtin_type;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (valid) {
if (p_target.mode == Address::TEMPORARY) {
Variant::Type result_type = Variant::get_operator_return_type(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type);
Variant::Type temp_type = temporaries[p_target.address].type;
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 951ae6ce99..cfff20f6d3 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -43,6 +43,7 @@
#include "core/config/engine.h"
#include "core/core_constants.h"
#include "core/io/file_access.h"
+#include "core/math/expression.h"
#ifdef TOOLS_ENABLED
#include "core/config/project_settings.h"
@@ -427,7 +428,30 @@ void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant>
}
String GDScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) {
- return "";
+ List<String> names;
+ List<Variant> values;
+ debug_get_stack_level_locals(p_level, &names, &values, p_max_subitems, p_max_depth);
+
+ Vector<String> name_vector;
+ for (const String &name : names) {
+ name_vector.push_back(name);
+ }
+
+ Array value_array;
+ for (const Variant &value : values) {
+ value_array.push_back(value);
+ }
+
+ Expression expression;
+ if (expression.parse(p_expression, name_vector) == OK) {
+ ScriptInstance *instance = debug_get_stack_level_instance(p_level);
+ if (instance) {
+ Variant return_val = expression.execute(value_array, instance->get_owner());
+ return return_val.get_construct_string();
+ }
+ }
+
+ return String();
}
void GDScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const {
@@ -1115,10 +1139,12 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
continue;
}
option = ScriptLanguage::CodeCompletionOption(member.function->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
- if (member.function->parameters.size() > 0) {
+ if (member.function->parameters.size() > 0 || (member.function->info.flags & METHOD_FLAG_VARARG)) {
option.insert_text += "(";
+ option.display += U"(\u2026)";
} else {
option.insert_text += "()";
+ option.display += "()";
}
break;
case GDScriptParser::ClassNode::Member::SIGNAL:
@@ -1160,6 +1186,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
if (!p_types_only && base_type.is_meta_type && base_type.kind != GDScriptParser::DataType::BUILTIN && base_type.kind != GDScriptParser::DataType::ENUM) {
ScriptLanguage::CodeCompletionOption option("new", ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, ScriptLanguage::LOCATION_LOCAL);
option.insert_text += "(";
+ option.display += U"(\u2026)";
r_result.insert(option.display, option);
}
@@ -1217,10 +1244,12 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
}
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()) {
+ if (E.arguments.size() || (E.flags & METHOD_FLAG_VARARG)) {
option.insert_text += "(";
+ option.display += U"(\u2026)";
} else {
option.insert_text += "()";
+ option.display += "()";
}
r_result.insert(option.display, option);
}
@@ -1303,10 +1332,12 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
}
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()) {
+ if (E.arguments.size() || (E.flags & METHOD_FLAG_VARARG)) {
option.insert_text += "(";
+ option.display += U"(\u2026)";
} else {
option.insert_text += "()";
+ option.display += "()";
}
r_result.insert(option.display, option);
}
@@ -1374,10 +1405,12 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
continue;
}
ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
- if (E.arguments.size()) {
+ if (E.arguments.size() || (E.flags & METHOD_FLAG_VARARG)) {
option.insert_text += "(";
+ option.display += U"(\u2026)";
} else {
option.insert_text += "()";
+ option.display += "()";
}
r_result.insert(option.display, option);
}
@@ -1409,8 +1442,10 @@ static void _find_identifiers(const GDScriptParser::CompletionContext &p_context
ScriptLanguage::CodeCompletionOption option(String(E), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
if (function.arguments.size() || (function.flags & METHOD_FLAG_VARARG)) {
option.insert_text += "(";
+ option.display += U"(\u2026)";
} else {
option.insert_text += "()";
+ option.display += "()";
}
r_result.insert(option.display, option);
}
@@ -1457,6 +1492,7 @@ static void _find_identifiers(const GDScriptParser::CompletionContext &p_context
while (*kwa) {
ScriptLanguage::CodeCompletionOption option(*kwa, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
option.insert_text += "(";
+ option.display += U"(\u2026)";
r_result.insert(option.display, option);
kwa++;
}
@@ -1467,6 +1503,7 @@ static void _find_identifiers(const GDScriptParser::CompletionContext &p_context
for (List<StringName>::Element *E = utility_func_names.front(); E; E = E->next()) {
ScriptLanguage::CodeCompletionOption option(E->get(), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
option.insert_text += "(";
+ option.display += U"(\u2026)"; // As all utility functions contain an argument or more, this is hardcoded here.
r_result.insert(option.display, option);
}
@@ -3448,7 +3485,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
}
String arg = arg_itr->name;
if (arg.contains(":")) {
- arg = arg.substr(0, arg.find(":"));
+ arg = arg.substr(0, arg.find_char(':'));
}
method_hint += arg;
if (use_type_hint) {
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index ee8d53639c..12e71004db 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -409,6 +409,10 @@ Error GDScriptParser::parse(const String &p_source_code, const String &p_script_
parse_program();
pop_multiline();
+#ifdef TOOLS_ENABLED
+ comment_data = tokenizer->get_comments();
+#endif
+
memdelete(text_tokenizer);
tokenizer = nullptr;
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 2ec33831a2..d40ba217c1 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -1601,6 +1601,8 @@ public:
#ifdef TOOLS_ENABLED
static HashMap<String, String> theme_color_names;
+
+ HashMap<int, GDScriptTokenizer::CommentData> comment_data;
#endif // TOOLS_ENABLED
GDScriptParser();
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.gd
new file mode 100644
index 0000000000..6367d50980
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.gd
@@ -0,0 +1,2 @@
+func test():
+ print(Vector3.Axis)
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.out b/modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.out
new file mode 100644
index 0000000000..9c476031f3
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_builtin_access.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Type "Axis" in base "Vector3" cannot be used on its own.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.gd
new file mode 100644
index 0000000000..badcd3a83c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.gd
@@ -0,0 +1,2 @@
+func test():
+ print(Variant.Operator)
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.out b/modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.out
new file mode 100644
index 0000000000..191acade73
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_global_access.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Type "Operator" in base "Variant" cannot be used on its own.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.gd
new file mode 100644
index 0000000000..e07998ddf6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.gd
@@ -0,0 +1,2 @@
+func test():
+ print(Node.ProcessMode)
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.out b/modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.out
new file mode 100644
index 0000000000..83671fc493
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_native_access.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Type "ProcessMode" in base "Node" cannot be used on its own.
diff --git a/modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.gd b/modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.gd
new file mode 100644
index 0000000000..4ccd7de994
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.gd
@@ -0,0 +1,28 @@
+extends Node
+
+@export var test_type_1 := TYPE_BOOL
+@export var test_type_2 := Variant.Type.TYPE_BOOL
+@export var test_type_3: Variant.Type
+
+@export var test_side_1 := SIDE_RIGHT
+@export var test_side_2 := Side.SIDE_RIGHT
+@export var test_side_3: Side
+
+@export var test_axis_1 := Vector3.AXIS_Y
+@export var test_axis_2 := Vector3.Axis.AXIS_Y
+@export var test_axis_3: Vector3.Axis
+
+@export var test_mode_1 := Node.PROCESS_MODE_ALWAYS
+@export var test_mode_2 := Node.ProcessMode.PROCESS_MODE_ALWAYS
+@export var test_mode_3: Node.ProcessMode
+
+func test():
+ for property in get_property_list():
+ if str(property.name).begins_with("test_"):
+ Utils.print_property_extended_info(property, self)
+
+func test_no_exec():
+ # GH-99309
+ var sprite: Sprite3D = $Sprite3D
+ sprite.axis = Vector3.AXIS_Y # No warning.
+ sprite.set_axis(Vector3.AXIS_Y) # No warning.
diff --git a/modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.out b/modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.out
new file mode 100644
index 0000000000..6c45dee323
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/global_builtin_and_native_enums.out
@@ -0,0 +1,25 @@
+GDTEST_OK
+var test_type_1: Variant.Type = 1
+ hint=ENUM hint_string="Type Nil:0,Type Bool:1,Type Int:2,Type Float:3,Type String:4,Type Vector 2:5,Type Vector 2i:6,Type Rect 2:7,Type Rect 2i:8,Type Vector 3:9,Type Vector 3i:10,Type Transform 2d:11,Type Vector 4:12,Type Vector 4i:13,Type Plane:14,Type Quaternion:15,Type Aabb:16,Type Basis:17,Type Transform 3d:18,Type Projection:19,Type Color:20,Type String Name:21,Type Node Path:22,Type Rid:23,Type Object:24,Type Callable:25,Type Signal:26,Type Dictionary:27,Type Array:28,Type Packed Byte Array:29,Type Packed Int 32 Array:30,Type Packed Int 64 Array:31,Type Packed Float 32 Array:32,Type Packed Float 64 Array:33,Type Packed String Array:34,Type Packed Vector 2 Array:35,Type Packed Vector 3 Array:36,Type Packed Color Array:37,Type Packed Vector 4 Array:38,Type Max:39" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Variant.Type"
+var test_type_2: Variant.Type = 1
+ hint=ENUM hint_string="Type Nil:0,Type Bool:1,Type Int:2,Type Float:3,Type String:4,Type Vector 2:5,Type Vector 2i:6,Type Rect 2:7,Type Rect 2i:8,Type Vector 3:9,Type Vector 3i:10,Type Transform 2d:11,Type Vector 4:12,Type Vector 4i:13,Type Plane:14,Type Quaternion:15,Type Aabb:16,Type Basis:17,Type Transform 3d:18,Type Projection:19,Type Color:20,Type String Name:21,Type Node Path:22,Type Rid:23,Type Object:24,Type Callable:25,Type Signal:26,Type Dictionary:27,Type Array:28,Type Packed Byte Array:29,Type Packed Int 32 Array:30,Type Packed Int 64 Array:31,Type Packed Float 32 Array:32,Type Packed Float 64 Array:33,Type Packed String Array:34,Type Packed Vector 2 Array:35,Type Packed Vector 3 Array:36,Type Packed Color Array:37,Type Packed Vector 4 Array:38,Type Max:39" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Variant.Type"
+var test_type_3: Variant.Type = 0
+ hint=ENUM hint_string="Type Nil:0,Type Bool:1,Type Int:2,Type Float:3,Type String:4,Type Vector 2:5,Type Vector 2i:6,Type Rect 2:7,Type Rect 2i:8,Type Vector 3:9,Type Vector 3i:10,Type Transform 2d:11,Type Vector 4:12,Type Vector 4i:13,Type Plane:14,Type Quaternion:15,Type Aabb:16,Type Basis:17,Type Transform 3d:18,Type Projection:19,Type Color:20,Type String Name:21,Type Node Path:22,Type Rid:23,Type Object:24,Type Callable:25,Type Signal:26,Type Dictionary:27,Type Array:28,Type Packed Byte Array:29,Type Packed Int 32 Array:30,Type Packed Int 64 Array:31,Type Packed Float 32 Array:32,Type Packed Float 64 Array:33,Type Packed String Array:34,Type Packed Vector 2 Array:35,Type Packed Vector 3 Array:36,Type Packed Color Array:37,Type Packed Vector 4 Array:38,Type Max:39" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Variant.Type"
+var test_side_1: Side = 2
+ hint=ENUM hint_string="Side Left:0,Side Top:1,Side Right:2,Side Bottom:3" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Side"
+var test_side_2: Side = 2
+ hint=ENUM hint_string="Side Left:0,Side Top:1,Side Right:2,Side Bottom:3" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Side"
+var test_side_3: Side = 0
+ hint=ENUM hint_string="Side Left:0,Side Top:1,Side Right:2,Side Bottom:3" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Side"
+var test_axis_1: Vector3.Axis = 1
+ hint=ENUM hint_string="Axis X:0,Axis Y:1,Axis Z:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Vector3.Axis"
+var test_axis_2: Vector3.Axis = 1
+ hint=ENUM hint_string="Axis X:0,Axis Y:1,Axis Z:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Vector3.Axis"
+var test_axis_3: Vector3.Axis = 0
+ hint=ENUM hint_string="Axis X:0,Axis Y:1,Axis Z:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Vector3.Axis"
+var test_mode_1: Node.ProcessMode = 3
+ hint=ENUM hint_string="Process Mode Inherit:0,Process Mode Pausable:1,Process Mode When Paused:2,Process Mode Always:3,Process Mode Disabled:4" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Node.ProcessMode"
+var test_mode_2: Node.ProcessMode = 3
+ hint=ENUM hint_string="Process Mode Inherit:0,Process Mode Pausable:1,Process Mode When Paused:2,Process Mode Always:3,Process Mode Disabled:4" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Node.ProcessMode"
+var test_mode_3: Node.ProcessMode = 0
+ hint=ENUM hint_string="Process Mode Inherit:0,Process Mode Pausable:1,Process Mode When Paused:2,Process Mode Always:3,Process Mode Disabled:4" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM class_name=&"Node.ProcessMode"
diff --git a/modules/gdscript/tests/scripts/completion/argument_options/argument_options.tscn b/modules/gdscript/tests/scripts/completion/argument_options/argument_options.tscn
index d3dea6b12b..082c87e708 100644
--- a/modules/gdscript/tests/scripts/completion/argument_options/argument_options.tscn
+++ b/modules/gdscript/tests/scripts/completion/argument_options/argument_options.tscn
@@ -1,3 +1,16 @@
[gd_scene load_steps=1 format=3 uid="uid://dl28pdkxcjvym"]
+[sub_resource type="Animation" id="Animation_d1pub"]
+resource_name = "bounce"
+
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_gs7mj"]
+_data = {
+"bounce": SubResource("Animation_d1pub")
+}
+
[node name="GetNode" type="Node"]
+
+[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
+libraries = {
+"": SubResource("AnimationLibrary_gs7mj")
+}
diff --git a/modules/gdscript/tests/scripts/completion/argument_options/play_inferred.cfg b/modules/gdscript/tests/scripts/completion/argument_options/play_inferred.cfg
new file mode 100644
index 0000000000..ca108a18c2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/argument_options/play_inferred.cfg
@@ -0,0 +1,6 @@
+[input]
+scene="res://completion/argument_options/argument_options.tscn"
+[output]
+include=[
+ {"display": "\"bounce\""},
+]
diff --git a/modules/gdscript/tests/scripts/completion/argument_options/play_inferred.gd b/modules/gdscript/tests/scripts/completion/argument_options/play_inferred.gd
new file mode 100644
index 0000000000..abeadbe5ee
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/argument_options/play_inferred.gd
@@ -0,0 +1,5 @@
+@onready var anim := $AnimationPlayer
+
+func test():
+ anim.play(➡)
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/argument_options/play_typed.cfg b/modules/gdscript/tests/scripts/completion/argument_options/play_typed.cfg
new file mode 100644
index 0000000000..ca108a18c2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/argument_options/play_typed.cfg
@@ -0,0 +1,6 @@
+[input]
+scene="res://completion/argument_options/argument_options.tscn"
+[output]
+include=[
+ {"display": "\"bounce\""},
+]
diff --git a/modules/gdscript/tests/scripts/completion/argument_options/play_typed.gd b/modules/gdscript/tests/scripts/completion/argument_options/play_typed.gd
new file mode 100644
index 0000000000..d11f81e985
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/argument_options/play_typed.gd
@@ -0,0 +1,5 @@
+@onready var anim: AnimationPlayer = $AnimationPlayer
+
+func test():
+ anim.play(➡)
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/argument_options/play_untyped.cfg b/modules/gdscript/tests/scripts/completion/argument_options/play_untyped.cfg
new file mode 100644
index 0000000000..ca108a18c2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/argument_options/play_untyped.cfg
@@ -0,0 +1,6 @@
+[input]
+scene="res://completion/argument_options/argument_options.tscn"
+[output]
+include=[
+ {"display": "\"bounce\""},
+]
diff --git a/modules/gdscript/tests/scripts/completion/argument_options/play_untyped.gd b/modules/gdscript/tests/scripts/completion/argument_options/play_untyped.gd
new file mode 100644
index 0000000000..4ddfd21ac6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/argument_options/play_untyped.gd
@@ -0,0 +1,5 @@
+@onready var anim = $AnimationPlayer
+
+func test():
+ anim.play(➡)
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.cfg b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.cfg
index e4759ac76b..a2c332adad 100644
--- a/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.cfg
+++ b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute.cfg
@@ -1,6 +1,6 @@
[output]
include=[
- {"display": "new"},
+ {"display": "new(…)"},
{"display": "SIZE_EXPAND"},
{"display": "SIZE_EXPAND_FILL"},
{"display": "SIZE_FILL"},
diff --git a/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.cfg b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.cfg
index e4759ac76b..a2c332adad 100644
--- a/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.cfg
+++ b/modules/gdscript/tests/scripts/completion/assignment_options/enum_attribute_identifier.cfg
@@ -1,6 +1,6 @@
[output]
include=[
- {"display": "new"},
+ {"display": "new(…)"},
{"display": "SIZE_EXPAND"},
{"display": "SIZE_EXPAND_FILL"},
{"display": "SIZE_FILL"},
diff --git a/modules/gdscript/tests/scripts/completion/common/identifiers_in_call.cfg b/modules/gdscript/tests/scripts/completion/common/identifiers_in_call.cfg
index 5f08f9c265..f2dff734b6 100644
--- a/modules/gdscript/tests/scripts/completion/common/identifiers_in_call.cfg
+++ b/modules/gdscript/tests/scripts/completion/common/identifiers_in_call.cfg
@@ -2,13 +2,13 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
; GDScript: identifiers.gd
@@ -16,8 +16,8 @@ include=[
{"display": "test_signal_2"},
{"display": "test_var_1"},
{"display": "test_var_2"},
- {"display": "test_func_1"},
- {"display": "test_func_2"},
+ {"display": "test_func_1(…)"},
+ {"display": "test_func_2(…)"},
{"display": "test_parameter_1"},
{"display": "test_parameter_2"},
{"display": "local_test_var_1"},
diff --git a/modules/gdscript/tests/scripts/completion/common/identifiers_in_function_body.cfg b/modules/gdscript/tests/scripts/completion/common/identifiers_in_function_body.cfg
index 5f08f9c265..f2dff734b6 100644
--- a/modules/gdscript/tests/scripts/completion/common/identifiers_in_function_body.cfg
+++ b/modules/gdscript/tests/scripts/completion/common/identifiers_in_function_body.cfg
@@ -2,13 +2,13 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
; GDScript: identifiers.gd
@@ -16,8 +16,8 @@ include=[
{"display": "test_signal_2"},
{"display": "test_var_1"},
{"display": "test_var_2"},
- {"display": "test_func_1"},
- {"display": "test_func_2"},
+ {"display": "test_func_1(…)"},
+ {"display": "test_func_2(…)"},
{"display": "test_parameter_1"},
{"display": "test_parameter_2"},
{"display": "local_test_var_1"},
diff --git a/modules/gdscript/tests/scripts/completion/common/identifiers_in_unclosed_call.cfg b/modules/gdscript/tests/scripts/completion/common/identifiers_in_unclosed_call.cfg
index 5f08f9c265..f2dff734b6 100644
--- a/modules/gdscript/tests/scripts/completion/common/identifiers_in_unclosed_call.cfg
+++ b/modules/gdscript/tests/scripts/completion/common/identifiers_in_unclosed_call.cfg
@@ -2,13 +2,13 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
; GDScript: identifiers.gd
@@ -16,8 +16,8 @@ include=[
{"display": "test_signal_2"},
{"display": "test_var_1"},
{"display": "test_var_2"},
- {"display": "test_func_1"},
- {"display": "test_func_2"},
+ {"display": "test_func_1(…)"},
+ {"display": "test_func_2(…)"},
{"display": "test_parameter_1"},
{"display": "test_parameter_2"},
{"display": "local_test_var_1"},
diff --git a/modules/gdscript/tests/scripts/completion/common/no_completion_in_string.cfg b/modules/gdscript/tests/scripts/completion/common/no_completion_in_string.cfg
index 462846c9b2..e012919051 100644
--- a/modules/gdscript/tests/scripts/completion/common/no_completion_in_string.cfg
+++ b/modules/gdscript/tests/scripts/completion/common/no_completion_in_string.cfg
@@ -2,14 +2,14 @@ scene="res://completion/get_node/get_node.tscn"
[output]
exclude=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
- {"display": "add_child"},
+ {"display": "add_child(…)"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
; GDScript: no_completion_in_string.gd
@@ -17,8 +17,8 @@ exclude=[
{"display": "test_signal_2"},
{"display": "test_var_1"},
{"display": "test_var_2"},
- {"display": "test_func_1"},
- {"display": "test_func_2"},
+ {"display": "test_func_1(…)"},
+ {"display": "test_func_2(…)"},
{"display": "test_parameter_1"},
{"display": "test_parameter_2"},
{"display": "local_test_var_1"},
diff --git a/modules/gdscript/tests/scripts/completion/common/self.cfg b/modules/gdscript/tests/scripts/completion/common/self.cfg
index 871a404e3a..dcce1df0d0 100644
--- a/modules/gdscript/tests/scripts/completion/common/self.cfg
+++ b/modules/gdscript/tests/scripts/completion/common/self.cfg
@@ -2,13 +2,13 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
; GDScript: self.gd
@@ -16,6 +16,6 @@ include=[
{"display": "test_signal_2"},
{"display": "test_var_1"},
{"display": "test_var_2"},
- {"display": "test_func_1"},
- {"display": "test_func_2"},
+ {"display": "test_func_1(…)"},
+ {"display": "test_func_2(…)"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg
index ae7d34d87d..319c5121b5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg
@@ -1,7 +1,7 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg
index ae7d34d87d..319c5121b5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg
@@ -1,7 +1,7 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local/local.cfg b/modules/gdscript/tests/scripts/completion/get_node/local/local.cfg
index ae7d34d87d..319c5121b5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local/local.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local/local.cfg
@@ -1,7 +1,7 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_infered/local_infered.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_infered/local_infered.cfg
index ae7d34d87d..319c5121b5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_infered/local_infered.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_infered/local_infered.cfg
@@ -1,7 +1,7 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/class_local_infered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/class_local_infered_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/class_local_infered_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/class_local_infered_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/native_local_infered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/native_local_infered_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/native_local_infered_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_infered_scene/native_local_infered_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg
index 72c0549d3b..d647135bc6 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg
index 1894e72c65..a6118908de 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg
@@ -3,18 +3,18 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; Area2D
- {"display": "get_overlapping_areas"},
+ {"display": "get_overlapping_areas()"},
{"display": "linear_damp"},
{"display": "area_entered"},
]
exclude=[
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg
index c8ab63f6d6..d8390ca33c 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg
@@ -3,18 +3,18 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; Area2D
- {"display": "get_overlapping_areas"},
+ {"display": "get_overlapping_areas()"},
{"display": "linear_damp"},
{"display": "area_entered"},
]
exclude=[
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member/member.cfg b/modules/gdscript/tests/scripts/completion/get_node/member/member.cfg
index ae7d34d87d..319c5121b5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member/member.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member/member.cfg
@@ -1,7 +1,7 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_infered/member_infered.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_infered/member_infered.cfg
index ae7d34d87d..319c5121b5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_infered/member_infered.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_infered/member_infered.cfg
@@ -1,7 +1,7 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/class_member_infered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/class_member_infered_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/class_member_infered_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/class_member_infered_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/native_member_infered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/native_member_infered_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/native_member_infered_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_infered_scene/native_member_infered_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg
index 72c0549d3b..d647135bc6 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg
index 9c580b711d..7518bf5ae5 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg
index 446198dd35..174fdcb184 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg
@@ -3,12 +3,12 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg
index 502038bef7..2f747e0bac 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg
@@ -3,7 +3,7 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
@@ -11,6 +11,6 @@ include=[
exclude=[
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg
index 1810e9fe5f..f060413898 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg
@@ -3,7 +3,7 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
@@ -11,6 +11,6 @@ include=[
exclude=[
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg
index 1894e72c65..a6118908de 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg
@@ -3,18 +3,18 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; Area2D
- {"display": "get_overlapping_areas"},
+ {"display": "get_overlapping_areas()"},
{"display": "linear_damp"},
{"display": "area_entered"},
]
exclude=[
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg
index c8ab63f6d6..d8390ca33c 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg
@@ -3,18 +3,18 @@ scene="res://completion/get_node/get_node.tscn"
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; Area2D
- {"display": "get_overlapping_areas"},
+ {"display": "get_overlapping_areas()"},
{"display": "linear_damp"},
{"display": "area_entered"},
]
exclude=[
; AnimationPlayer
{"display": "autoplay"},
- {"display": "play"},
+ {"display": "play(…)"},
{"display": "animation_changed"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/infered.cfg b/modules/gdscript/tests/scripts/completion/types/local/infered.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/local/infered.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/local/infered.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/no_type.cfg b/modules/gdscript/tests/scripts/completion/types/local/no_type.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/local/no_type.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/local/no_type.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/typehint.cfg b/modules/gdscript/tests/scripts/completion/types/local/typehint.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/local/typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/local/typehint.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/typehint_broad.cfg b/modules/gdscript/tests/scripts/completion/types/local/typehint_broad.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/local/typehint_broad.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/local/typehint_broad.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.cfg b/modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/local/typehint_incompatible.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/infered.cfg b/modules/gdscript/tests/scripts/completion/types/member/infered.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/member/infered.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/member/infered.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/no_type.cfg b/modules/gdscript/tests/scripts/completion/types/member/no_type.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/member/no_type.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/member/no_type.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/typehint.cfg b/modules/gdscript/tests/scripts/completion/types/member/typehint.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/member/typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/member/typehint.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/typehint_broad.cfg b/modules/gdscript/tests/scripts/completion/types/member/typehint_broad.cfg
index 81401316ec..d32bbac65e 100644
--- a/modules/gdscript/tests/scripts/completion/types/member/typehint_broad.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/member/typehint_broad.cfg
@@ -1,13 +1,13 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
]
exclude=[
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.cfg b/modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.cfg
index 8b68d51a89..050b0d61a3 100644
--- a/modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.cfg
+++ b/modules/gdscript/tests/scripts/completion/types/member/typehint_incompatible.cfg
@@ -1,12 +1,12 @@
[output]
include=[
; Node
- {"display": "add_child"},
+ {"display": "add_child(…)"},
{"display": "owner"},
{"display": "child_entered_tree"},
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
- {"display": "func_of_a"},
+ {"display": "func_of_a()"},
{"display": "signal_of_a"},
]
diff --git a/modules/gdscript/tests/scripts/runtime/errors/division_by_zero.gd b/modules/gdscript/tests/scripts/runtime/errors/division_by_zero.gd
new file mode 100644
index 0000000000..ace5397f40
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/division_by_zero.gd
@@ -0,0 +1,3 @@
+func test():
+ var integer: int = 1
+ integer /= 0
diff --git a/modules/gdscript/tests/scripts/runtime/errors/division_by_zero.out b/modules/gdscript/tests/scripts/runtime/errors/division_by_zero.out
new file mode 100644
index 0000000000..6a9d11cd77
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/division_by_zero.out
@@ -0,0 +1,6 @@
+GDTEST_RUNTIME_ERROR
+>> SCRIPT ERROR
+>> on function: test()
+>> runtime/errors/division_by_zero.gd
+>> 3
+>> Division by zero error in operator '/'.
diff --git a/modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.gd b/modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.gd
new file mode 100644
index 0000000000..99792e4e32
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.gd
@@ -0,0 +1,3 @@
+func test():
+ var integer: int = 1
+ integer %= 0
diff --git a/modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.out b/modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.out
new file mode 100644
index 0000000000..79c512888f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/modulo_by_zero.out
@@ -0,0 +1,6 @@
+GDTEST_RUNTIME_ERROR
+>> SCRIPT ERROR
+>> on function: test()
+>> runtime/errors/modulo_by_zero.gd
+>> 3
+>> Modulo by zero error in operator '%'.
diff --git a/modules/gdscript/tests/scripts/runtime/features/stringify.gd b/modules/gdscript/tests/scripts/runtime/features/stringify.gd
index 8579baf876..69aecec6a8 100644
--- a/modules/gdscript/tests/scripts/runtime/features/stringify.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/stringify.gd
@@ -4,21 +4,25 @@ func test():
print(-1.25, 0.25, 1.25)
print("hello world")
- print(Vector2(0.25, 0.25))
+ print(Vector2(0.25, 1))
print(Vector2i(0, 0))
- print(Rect2(0.25, 0.25, 0.5, 0.5))
+ print(Rect2(0.25, 0.25, 0.5, 1))
print(Rect2i(0, 0, 0, 0))
- print(Vector3(0.25, 0.25, 0.25))
+ print(Vector3(0.25, 0.25, 1))
print(Vector3i(0, 0, 0))
+ print(Vector4(0.25, 0.25, 0.25, 1))
+ print(Vector4i(0, 0, 0, 0))
+
print(Transform2D.IDENTITY)
print(Plane(1, 2, 3, 4))
print(Quaternion(1, 2, 3, 4))
print(AABB(Vector3.ZERO, Vector3.ONE))
print(Basis.from_euler(Vector3(0, 0, 0)))
print(Transform3D.IDENTITY)
+ print(Projection.IDENTITY)
print(Color(1, 2, 3, 4))
print(StringName("hello"))
diff --git a/modules/gdscript/tests/scripts/runtime/features/stringify.out b/modules/gdscript/tests/scripts/runtime/features/stringify.out
index 2463d70ef4..b044f8105d 100644
--- a/modules/gdscript/tests/scripts/runtime/features/stringify.out
+++ b/modules/gdscript/tests/scripts/runtime/features/stringify.out
@@ -3,18 +3,21 @@ truefalse
-101
-1.250.251.25
hello world
-(0.25, 0.25)
+(0.25, 1.0)
(0, 0)
-[P: (0.25, 0.25), S: (0.5, 0.5)]
+[P: (0.25, 0.25), S: (0.5, 1.0)]
[P: (0, 0), S: (0, 0)]
-(0.25, 0.25, 0.25)
+(0.25, 0.25, 1.0)
(0, 0, 0)
+(0.25, 0.25, 0.25, 1.0)
+(0, 0, 0, 0)
[X: (1.0, 0.0), Y: (0.0, 1.0), O: (0.0, 0.0)]
[N: (1.0, 2.0, 3.0), D: 4]
(1, 2, 3, 4)
[P: (0.0, 0.0, 0.0), S: (1.0, 1.0, 1.0)]
[X: (1.0, 0.0, 0.0), Y: (0.0, 1.0, 0.0), Z: (0.0, 0.0, 1.0)]
[X: (1.0, 0.0, 0.0), Y: (0.0, 1.0, 0.0), Z: (0.0, 0.0, 1.0), O: (0.0, 0.0, 0.0)]
+[X: (1.0, 0.0, 0.0, 0.0), Y: (0.0, 1.0, 0.0, 0.0), Z: (0.0, 0.0, 1.0, 0.0), W: (0.0, 0.0, 0.0, 1.0)]
(1.0, 2.0, 3.0, 4.0)
hello
hello/world
@@ -32,4 +35,4 @@ Node::[signal]property_list_changed
[(1.0, 1.0), (0.0, 0.0)]
[(1.0, 1.0, 1.0), (0.0, 0.0, 0.0)]
[(1.0, 0.0, 0.0, 1.0), (0.0, 0.0, 1.0, 1.0), (0.0, 1.0, 0.0, 1.0)]
-[(1, 1, 1, 1), (0, 0, 0, 0)]
+[(1.0, 1.0, 1.0, 1.0), (0.0, 0.0, 0.0, 0.0)]
diff --git a/modules/gltf/doc_classes/GLTFAccessor.xml b/modules/gltf/doc_classes/GLTFAccessor.xml
index 04fa2a9835..271f098803 100644
--- a/modules/gltf/doc_classes/GLTFAccessor.xml
+++ b/modules/gltf/doc_classes/GLTFAccessor.xml
@@ -102,13 +102,13 @@
Component type "UNSIGNED_INT". The value is [code]0x1405[/code] which comes from OpenGL. This indicates data is stored in 4-byte or 32-bit unsigned integers. This is a core part of the glTF specification.
</constant>
<constant name="COMPONENT_TYPE_SINGLE_FLOAT" value="5126" enum="GLTFComponentType">
- Component type "FLOAT". The value is [code]0x1406[/code] which comes from OpenGL. This indicates data is stored in 4-byte or 32-bit floating point numbers. This is a core part of the glTF specification.
+ Component type "FLOAT". The value is [code]0x1406[/code] which comes from OpenGL. This indicates data is stored in 4-byte or 32-bit floating-point numbers. This is a core part of the glTF specification.
</constant>
<constant name="COMPONENT_TYPE_DOUBLE_FLOAT" value="5130" enum="GLTFComponentType">
- Component type "DOUBLE". The value is [code]0x140A[/code] which comes from OpenGL. This indicates data is stored in 8-byte or 64-bit floating point numbers. This is NOT a core part of the glTF specification, and may not be supported by all glTF importers. May be used by some extensions including [code]KHR_interactivity[/code].
+ Component type "DOUBLE". The value is [code]0x140A[/code] which comes from OpenGL. This indicates data is stored in 8-byte or 64-bit floating-point numbers. This is NOT a core part of the glTF specification, and may not be supported by all glTF importers. May be used by some extensions including [code]KHR_interactivity[/code].
</constant>
<constant name="COMPONENT_TYPE_HALF_FLOAT" value="5131" enum="GLTFComponentType">
- Component type "HALF_FLOAT". The value is [code]0x140B[/code] which comes from OpenGL. This indicates data is stored in 2-byte or 16-bit floating point numbers. This is NOT a core part of the glTF specification, and may not be supported by all glTF importers. May be used by some extensions including [code]KHR_interactivity[/code].
+ Component type "HALF_FLOAT". The value is [code]0x140B[/code] which comes from OpenGL. This indicates data is stored in 2-byte or 16-bit floating-point numbers. This is NOT a core part of the glTF specification, and may not be supported by all glTF importers. May be used by some extensions including [code]KHR_interactivity[/code].
</constant>
<constant name="COMPONENT_TYPE_SIGNED_LONG" value="5134" enum="GLTFComponentType">
Component type "LONG". The value is [code]0x140E[/code] which comes from OpenGL. This indicates data is stored in 8-byte or 64-bit signed integers. This is NOT a core part of the glTF specification, and may not be supported by all glTF importers. May be used by some extensions including [code]KHR_interactivity[/code].
diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml
index 376c3c89f5..c81c2f09f0 100644
--- a/modules/gltf/doc_classes/GLTFState.xml
+++ b/modules/gltf/doc_classes/GLTFState.xml
@@ -306,7 +306,7 @@
The binary buffer attached to a .glb file.
</member>
<member name="import_as_skeleton_bones" type="bool" setter="set_import_as_skeleton_bones" getter="get_import_as_skeleton_bones" default="false">
- True to force all GLTFNodes in the document to be bones of a single Skeleton3D godot node.
+ If [code]true[/code], forces all GLTFNodes in the document to be bones of a single [Skeleton3D] Godot node.
</member>
<member name="json" type="Dictionary" setter="set_json" getter="get_json" default="{}">
The original raw JSON document corresponding to this GLTFState.
diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp
index 2db46adef4..5ba9ee3fa6 100644
--- a/modules/gltf/editor/editor_scene_importer_blend.cpp
+++ b/modules/gltf/editor/editor_scene_importer_blend.cpp
@@ -80,7 +80,7 @@ static bool _get_blender_version(const String &p_path, int &r_major, int &r_mino
}
pipe = pipe.substr(bl);
pipe = pipe.replace_first("Blender ", "");
- int pp = pipe.find(".");
+ int pp = pipe.find_char('.');
if (pp == -1) {
if (r_err) {
*r_err = vformat(TTR("Couldn't extract version information from Blender executable at: %s."), p_path);
@@ -96,7 +96,7 @@ static bool _get_blender_version(const String &p_path, int &r_major, int &r_mino
return false;
}
- int pp2 = pipe.find(".", pp + 1);
+ int pp2 = pipe.find_char('.', pp + 1);
r_minor = pp2 > pp ? pipe.substr(pp + 1, pp2 - pp - 1).to_int() : 0;
return true;
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 7cac61304f..2f36c29ec4 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -689,7 +689,7 @@ void GLTFDocument::_compute_node_heights(Ref<GLTFState> p_state) {
}
static Vector<uint8_t> _parse_base64_uri(const String &p_uri) {
- int start = p_uri.find(",");
+ int start = p_uri.find_char(',');
ERR_FAIL_COND_V(start == -1, Vector<uint8_t>());
CharString substr = p_uri.substr(start + 1).ascii();
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp
index caa7a79874..0d522a0562 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp
@@ -646,6 +646,7 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D
Ref<InputEventKey> k = p_event;
if (k.is_valid() && k->is_pressed() && !k->is_echo()) {
+ // Transform mode (toggle button):
// If we are in Transform mode we pass the events to the 3D editor,
// but if the Transform mode shortcut is pressed again, we go back to Selection mode.
if (mode_buttons_group->get_pressed_button() == transform_mode_button) {
@@ -656,7 +657,7 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D
}
return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
-
+ // Tool modes and tool actions:
for (BaseButton *b : viewport_shortcut_buttons) {
if (b->is_disabled()) {
continue;
@@ -673,9 +674,7 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
- }
-
- if (k.is_valid() && k->is_pressed() && !k->is_echo()) {
+ // Hard key actions:
if (k->get_keycode() == Key::ESCAPE) {
if (input_action == INPUT_PASTE) {
_clear_clipboard_data();
@@ -692,7 +691,7 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
-
+ // Options menu shortcuts:
Ref<Shortcut> ed_shortcut = ED_GET_SHORTCUT("grid_map/previous_floor");
if (ed_shortcut.is_valid() && ed_shortcut->matches_event(p_event)) {
accept_event();
@@ -1352,7 +1351,6 @@ GridMapEditor::GridMapEditor() {
callable_mp(this, &GridMapEditor::_on_tool_mode_changed).unbind(1));
mode_buttons->add_child(select_mode_button);
viewport_shortcut_buttons.push_back(select_mode_button);
- select_mode_button->set_pressed(true);
erase_mode_button = memnew(Button);
erase_mode_button->set_theme_type_variation("FlatButton");
@@ -1396,6 +1394,7 @@ GridMapEditor::GridMapEditor() {
fill_action_button->connect(SceneStringName(pressed),
callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_SELECTION_FILL));
action_buttons->add_child(fill_action_button);
+ viewport_shortcut_buttons.push_back(fill_action_button);
move_action_button = memnew(Button);
move_action_button->set_theme_type_variation("FlatButton");
@@ -1403,6 +1402,7 @@ GridMapEditor::GridMapEditor() {
move_action_button->connect(SceneStringName(pressed),
callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_SELECTION_CUT));
action_buttons->add_child(move_action_button);
+ viewport_shortcut_buttons.push_back(move_action_button);
duplicate_action_button = memnew(Button);
duplicate_action_button->set_theme_type_variation("FlatButton");
@@ -1410,6 +1410,7 @@ GridMapEditor::GridMapEditor() {
duplicate_action_button->connect(SceneStringName(pressed),
callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_SELECTION_DUPLICATE));
action_buttons->add_child(duplicate_action_button);
+ viewport_shortcut_buttons.push_back(duplicate_action_button);
delete_action_button = memnew(Button);
delete_action_button->set_theme_type_variation("FlatButton");
@@ -1417,6 +1418,7 @@ GridMapEditor::GridMapEditor() {
delete_action_button->connect(SceneStringName(pressed),
callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_SELECTION_CLEAR));
action_buttons->add_child(delete_action_button);
+ viewport_shortcut_buttons.push_back(delete_action_button);
vsep = memnew(VSeparator);
toolbar->add_child(vsep);
@@ -1430,6 +1432,7 @@ GridMapEditor::GridMapEditor() {
rotate_x_button->connect(SceneStringName(pressed),
callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_CURSOR_ROTATE_X));
rotation_buttons->add_child(rotate_x_button);
+ viewport_shortcut_buttons.push_back(rotate_x_button);
rotate_y_button = memnew(Button);
rotate_y_button->set_theme_type_variation("FlatButton");
@@ -1437,6 +1440,7 @@ GridMapEditor::GridMapEditor() {
rotate_y_button->connect(SceneStringName(pressed),
callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_CURSOR_ROTATE_Y));
rotation_buttons->add_child(rotate_y_button);
+ viewport_shortcut_buttons.push_back(rotate_y_button);
rotate_z_button = memnew(Button);
rotate_z_button->set_theme_type_variation("FlatButton");
@@ -1444,6 +1448,7 @@ GridMapEditor::GridMapEditor() {
rotate_z_button->connect(SceneStringName(pressed),
callable_mp(this, &GridMapEditor::_menu_option).bind(MENU_OPTION_CURSOR_ROTATE_Z));
rotation_buttons->add_child(rotate_z_button);
+ viewport_shortcut_buttons.push_back(rotate_z_button);
// Wide empty separation control. (like BoxContainer::add_spacer())
Control *c = memnew(Control);
@@ -1456,9 +1461,9 @@ GridMapEditor::GridMapEditor() {
floor->set_max(32767);
floor->set_step(1);
floor->set_tooltip_text(
- TTR(vformat("Change Grid Floor:\nPrevious Plane (%s)\nNext Plane (%s)",
+ vformat(TTR("Change Grid Floor:\nPrevious Plane (%s)\nNext Plane (%s)"),
ED_GET_SHORTCUT("grid_map/previous_floor")->get_as_text(),
- ED_GET_SHORTCUT("grid_map/next_floor")->get_as_text())));
+ ED_GET_SHORTCUT("grid_map/next_floor")->get_as_text()));
toolbar->add_child(floor);
floor->get_line_edit()->add_theme_constant_override("minimum_character_width", 2);
floor->get_line_edit()->set_context_menu_enabled(false);
@@ -1718,6 +1723,10 @@ bool GridMapEditorPlugin::handles(Object *p_object) const {
void GridMapEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
+ BaseButton *button = grid_map_editor->mode_buttons_group->get_pressed_button();
+ if (button == nullptr) {
+ grid_map_editor->select_mode_button->set_pressed(true);
+ }
grid_map_editor->_on_tool_mode_changed();
panel_button->show();
EditorNode::get_bottom_panel()->make_item_visible(grid_map_editor);
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index 8ba6f9e2ba..bd71e29d0a 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -247,7 +247,9 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
}
if (p_step_function) {
- p_step_function(0.1, RTR("Determining optimal atlas size"), p_bake_userdata, true);
+ if (p_step_function(0.1, RTR("Determining optimal atlas size"), p_bake_userdata, true)) {
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
atlas_size = Size2i(max, max);
@@ -324,7 +326,9 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
emission_images.resize(atlas_slices);
if (p_step_function) {
- p_step_function(0.2, RTR("Blitting albedo and emission"), p_bake_userdata, true);
+ if (p_step_function(0.2, RTR("Blitting albedo and emission"), p_bake_userdata, true)) {
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
for (int i = 0; i < atlas_slices; i++) {
@@ -1013,7 +1017,9 @@ LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDSh
if (p_step_function) {
int percent = (s + 1) * 100 / p_atlas_slices;
float p = float(s) / p_atlas_slices * 0.1;
- p_step_function(0.8 + p, vformat(RTR("Denoising %d%%"), percent), p_bake_userdata, false);
+ if (p_step_function(0.8 + p, vformat(RTR("Denoising %d%%"), percent), p_bake_userdata, false)) {
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
}
@@ -1265,7 +1271,15 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
rd->buffer_update(bake_parameters_buffer, 0, sizeof(BakeParameters), &bake_parameters);
if (p_step_function) {
- p_step_function(0.47, RTR("Preparing shaders"), p_bake_userdata, true);
+ if (p_step_function(0.47, RTR("Preparing shaders"), p_bake_userdata, true)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
//shaders
@@ -1497,7 +1511,17 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
rd->sync();
if (p_step_function) {
- p_step_function(0.49, RTR("Un-occluding geometry"), p_bake_userdata, true);
+ if (p_step_function(0.49, RTR("Un-occluding geometry"), p_bake_userdata, true)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
PushConstant push_constant;
@@ -1539,7 +1563,17 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
}
if (p_step_function) {
- p_step_function(0.5, RTR("Plot direct lighting"), p_bake_userdata, true);
+ if (p_step_function(0.5, RTR("Plot direct lighting"), p_bake_userdata, true)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
// Set ray count to the quality used for direct light and bounces.
@@ -1699,7 +1733,17 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
rd->sync();
if (p_step_function) {
- p_step_function(0.6, RTR("Integrate indirect lighting"), p_bake_userdata, true);
+ if (p_step_function(0.6, RTR("Integrate indirect lighting"), p_bake_userdata, true)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
int count = 0;
@@ -1738,7 +1782,17 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
int total = (atlas_slices * x_regions * y_regions * ray_iterations);
int percent = count * 100 / total;
float p = float(count) / total * 0.1;
- p_step_function(0.6 + p, vformat(RTR("Integrate indirect lighting %d%%"), percent), p_bake_userdata, false);
+ if (p_step_function(0.6 + p, vformat(RTR("Integrate indirect lighting %d%%"), percent), p_bake_userdata, false)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
}
}
@@ -1754,7 +1808,20 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
light_probe_buffer = rd->storage_buffer_create(sizeof(float) * 4 * 9 * probe_positions.size());
if (p_step_function) {
- p_step_function(0.7, RTR("Baking light probes"), p_bake_userdata, true);
+ if (p_step_function(0.7, RTR("Baking light probes"), p_bake_userdata, true)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ if (probe_positions.size() > 0) {
+ rd->free(light_probe_buffer);
+ }
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
Vector<RD::Uniform> uniforms;
@@ -1822,7 +1889,20 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
if (p_step_function) {
int percent = i * 100 / ray_iterations;
float p = float(i) / ray_iterations * 0.1;
- p_step_function(0.7 + p, vformat(RTR("Integrating light probes %d%%"), percent), p_bake_userdata, false);
+ if (p_step_function(0.7 + p, vformat(RTR("Integrating light probes %d%%"), percent), p_bake_userdata, false)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ if (probe_positions.size() > 0) {
+ rd->free(light_probe_buffer);
+ }
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
}
}
@@ -1844,7 +1924,20 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
if (p_use_denoiser) {
if (p_step_function) {
- p_step_function(0.8, RTR("Denoising"), p_bake_userdata, true);
+ if (p_step_function(0.8, RTR("Denoising"), p_bake_userdata, true)) {
+ FREE_TEXTURES
+ FREE_BUFFERS
+ FREE_RASTER_RESOURCES
+ FREE_COMPUTE_RESOURCES
+ if (probe_positions.size() > 0) {
+ rd->free(light_probe_buffer);
+ }
+ memdelete(rd);
+ if (rcd != nullptr) {
+ memdelete(rcd);
+ }
+ return BAKE_ERROR_USER_ABORTED;
+ }
}
{
diff --git a/modules/lightmapper_rd/lm_common_inc.glsl b/modules/lightmapper_rd/lm_common_inc.glsl
index 98d11b9e69..962e444911 100644
--- a/modules/lightmapper_rd/lm_common_inc.glsl
+++ b/modules/lightmapper_rd/lm_common_inc.glsl
@@ -1,4 +1,3 @@
-
/* SET 0, static data that does not change between any call */
layout(set = 0, binding = 0) uniform BakeParameters {
diff --git a/modules/mbedtls/stream_peer_mbedtls.cpp b/modules/mbedtls/stream_peer_mbedtls.cpp
index b4200410fb..3af66f6d83 100644
--- a/modules/mbedtls/stream_peer_mbedtls.cpp
+++ b/modules/mbedtls/stream_peer_mbedtls.cpp
@@ -166,21 +166,24 @@ Error StreamPeerMbedTLS::put_partial_data(const uint8_t *p_data, int p_bytes, in
return OK;
}
- int ret = mbedtls_ssl_write(tls_ctx->get_context(), p_data, p_bytes);
- if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
- // Non blocking IO
- ret = 0;
- } else if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
- // Clean close
- disconnect_from_stream();
- return ERR_FILE_EOF;
- } else if (ret <= 0) {
- TLSContextMbedTLS::print_mbedtls_error(ret);
- disconnect_from_stream();
- return ERR_CONNECTION_ERROR;
- }
+ do {
+ int ret = mbedtls_ssl_write(tls_ctx->get_context(), &p_data[r_sent], p_bytes - r_sent);
+ if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+ // Non blocking IO.
+ break;
+ } else if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
+ // Clean close
+ disconnect_from_stream();
+ return ERR_FILE_EOF;
+ } else if (ret <= 0) {
+ TLSContextMbedTLS::print_mbedtls_error(ret);
+ disconnect_from_stream();
+ return ERR_CONNECTION_ERROR;
+ }
+ r_sent += ret;
+
+ } while (r_sent < p_bytes);
- r_sent = ret;
return OK;
}
@@ -209,20 +212,25 @@ Error StreamPeerMbedTLS::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r
r_received = 0;
- int ret = mbedtls_ssl_read(tls_ctx->get_context(), p_buffer, p_bytes);
- if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
- ret = 0; // non blocking io
- } else if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
- // Clean close
- disconnect_from_stream();
- return ERR_FILE_EOF;
- } else if (ret <= 0) {
- TLSContextMbedTLS::print_mbedtls_error(ret);
- disconnect_from_stream();
- return ERR_CONNECTION_ERROR;
- }
+ do {
+ int ret = mbedtls_ssl_read(tls_ctx->get_context(), &p_buffer[r_received], p_bytes - r_received);
+ if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+ // Non blocking IO.
+ break;
+ } else if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
+ // Clean close
+ disconnect_from_stream();
+ return ERR_FILE_EOF;
+ } else if (ret <= 0) {
+ TLSContextMbedTLS::print_mbedtls_error(ret);
+ disconnect_from_stream();
+ return ERR_CONNECTION_ERROR;
+ }
+
+ r_received += ret;
+
+ } while (r_received < p_bytes);
- r_received = ret;
return OK;
}
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 380b401683..ec9c123f8d 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -2817,7 +2817,7 @@ Ref<Resource> ResourceFormatLoaderCSharpScript::load(const String &p_path, const
if (p_path.begins_with("csharp://")) {
// This is a virtual path used by generic types, extract the real path.
real_path = "res://" + p_path.trim_prefix("csharp://");
- real_path = real_path.substr(0, real_path.rfind(":"));
+ real_path = real_path.substr(0, real_path.rfind_char(':'));
}
Ref<CSharpScript> scr;
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ExportDiagnosticsTests.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ExportDiagnosticsTests.cs
index 6425c723dd..fe511d67ef 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ExportDiagnosticsTests.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ExportDiagnosticsTests.cs
@@ -74,4 +74,31 @@ public class ExportDiagnosticsTests
}
);
}
+
+ [Fact]
+ public async void ExportToolButtonInNonToolClass()
+ {
+ await CSharpSourceGeneratorVerifier<ScriptPropertiesGenerator>.Verify(
+ new string[] { "ExportDiagnostics_GD0108.cs" },
+ new string[] { "ExportDiagnostics_GD0108_ScriptProperties.generated.cs" }
+ );
+ }
+
+ [Fact]
+ public async void ExportAndExportToolButtonOnSameMember()
+ {
+ await CSharpSourceGeneratorVerifier<ScriptPropertiesGenerator>.Verify(
+ new string[] { "ExportDiagnostics_GD0109.cs" },
+ new string[] { "ExportDiagnostics_GD0109_ScriptProperties.generated.cs" }
+ );
+ }
+
+ [Fact]
+ public async void ExportToolButtonOnNonCallable()
+ {
+ await CSharpSourceGeneratorVerifier<ScriptPropertiesGenerator>.Verify(
+ new string[] { "ExportDiagnostics_GD0110.cs" },
+ new string[] { "ExportDiagnostics_GD0110_ScriptProperties.generated.cs" }
+ );
+ }
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertiesGeneratorTests.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertiesGeneratorTests.cs
index 724fb164e0..9693cba9ce 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertiesGeneratorTests.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPropertiesGeneratorTests.cs
@@ -66,4 +66,13 @@ public class ScriptPropertiesGeneratorTests
"AbstractGenericNode(Of T)_ScriptProperties.generated.cs"
);
}
+
+ [Fact]
+ public async void ExportedButtons()
+ {
+ await CSharpSourceGeneratorVerifier<ScriptPropertiesGenerator>.Verify(
+ "ExportedToolButtons.cs",
+ "ExportedToolButtons_ScriptProperties.generated.cs"
+ );
+ }
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/EventSignals_ScriptSignals.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/EventSignals_ScriptSignals.generated.cs
index f54058b0d9..5af859c06b 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/EventSignals_ScriptSignals.generated.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/EventSignals_ScriptSignals.generated.cs
@@ -32,9 +32,9 @@ partial class EventSignals
add => backing_MySignal += value;
remove => backing_MySignal -= value;
}
- protected void EmitSignalMySignal(string str, int num)
+ protected void EmitSignalMySignal(string @str, int @num)
{
- EmitSignal(SignalName.MySignal, str, num);
+ EmitSignal(SignalName.MySignal, @str, @num);
}
/// <inheritdoc/>
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0108_ScriptProperties.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0108_ScriptProperties.generated.cs
new file mode 100644
index 0000000000..77114a7c93
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0108_ScriptProperties.generated.cs
@@ -0,0 +1,48 @@
+using Godot;
+using Godot.NativeInterop;
+
+partial class ExportDiagnostics_GD0108
+{
+#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword
+ /// <summary>
+ /// Cached StringNames for the properties and fields contained in this class, for fast lookup.
+ /// </summary>
+ public new class PropertyName : global::Godot.Node.PropertyName {
+ /// <summary>
+ /// Cached name for the 'MyButton' field.
+ /// </summary>
+ public new static readonly global::Godot.StringName @MyButton = "MyButton";
+ }
+ /// <inheritdoc/>
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
+ protected override bool SetGodotClassPropertyValue(in godot_string_name name, in godot_variant value)
+ {
+ if (name == PropertyName.@MyButton) {
+ this.@MyButton = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Callable>(value);
+ return true;
+ }
+ return base.SetGodotClassPropertyValue(name, value);
+ }
+ /// <inheritdoc/>
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
+ protected override bool GetGodotClassPropertyValue(in godot_string_name name, out godot_variant value)
+ {
+ if (name == PropertyName.@MyButton) {
+ value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Callable>(this.@MyButton);
+ return true;
+ }
+ return base.GetGodotClassPropertyValue(name, out value);
+ }
+ /// <summary>
+ /// Get the property information for all the properties declared in this class.
+ /// This method is used by Godot to register the available properties in the editor.
+ /// Do not call this method.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
+ internal new static global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo> GetGodotPropertyList()
+ {
+ var properties = new global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>();
+ return properties;
+ }
+#pragma warning restore CS0109
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0109_ScriptProperties.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0109_ScriptProperties.generated.cs
new file mode 100644
index 0000000000..fc4547f2c1
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0109_ScriptProperties.generated.cs
@@ -0,0 +1,48 @@
+using Godot;
+using Godot.NativeInterop;
+
+partial class ExportDiagnostics_GD0109
+{
+#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword
+ /// <summary>
+ /// Cached StringNames for the properties and fields contained in this class, for fast lookup.
+ /// </summary>
+ public new class PropertyName : global::Godot.Node.PropertyName {
+ /// <summary>
+ /// Cached name for the 'MyButton' field.
+ /// </summary>
+ public new static readonly global::Godot.StringName @MyButton = "MyButton";
+ }
+ /// <inheritdoc/>
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
+ protected override bool SetGodotClassPropertyValue(in godot_string_name name, in godot_variant value)
+ {
+ if (name == PropertyName.@MyButton) {
+ this.@MyButton = global::Godot.NativeInterop.VariantUtils.ConvertTo<global::Godot.Callable>(value);
+ return true;
+ }
+ return base.SetGodotClassPropertyValue(name, value);
+ }
+ /// <inheritdoc/>
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
+ protected override bool GetGodotClassPropertyValue(in godot_string_name name, out godot_variant value)
+ {
+ if (name == PropertyName.@MyButton) {
+ value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Callable>(this.@MyButton);
+ return true;
+ }
+ return base.GetGodotClassPropertyValue(name, out value);
+ }
+ /// <summary>
+ /// Get the property information for all the properties declared in this class.
+ /// This method is used by Godot to register the available properties in the editor.
+ /// Do not call this method.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
+ internal new static global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo> GetGodotPropertyList()
+ {
+ var properties = new global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>();
+ return properties;
+ }
+#pragma warning restore CS0109
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0110_ScriptProperties.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0110_ScriptProperties.generated.cs
new file mode 100644
index 0000000000..d1aac17557
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0110_ScriptProperties.generated.cs
@@ -0,0 +1,48 @@
+using Godot;
+using Godot.NativeInterop;
+
+partial class ExportDiagnostics_GD0110
+{
+#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword
+ /// <summary>
+ /// Cached StringNames for the properties and fields contained in this class, for fast lookup.
+ /// </summary>
+ public new class PropertyName : global::Godot.Node.PropertyName {
+ /// <summary>
+ /// Cached name for the 'MyButton' field.
+ /// </summary>
+ public new static readonly global::Godot.StringName @MyButton = "MyButton";
+ }
+ /// <inheritdoc/>
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
+ protected override bool SetGodotClassPropertyValue(in godot_string_name name, in godot_variant value)
+ {
+ if (name == PropertyName.@MyButton) {
+ this.@MyButton = global::Godot.NativeInterop.VariantUtils.ConvertTo<string>(value);
+ return true;
+ }
+ return base.SetGodotClassPropertyValue(name, value);
+ }
+ /// <inheritdoc/>
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
+ protected override bool GetGodotClassPropertyValue(in godot_string_name name, out godot_variant value)
+ {
+ if (name == PropertyName.@MyButton) {
+ value = global::Godot.NativeInterop.VariantUtils.CreateFrom<string>(this.@MyButton);
+ return true;
+ }
+ return base.GetGodotClassPropertyValue(name, out value);
+ }
+ /// <summary>
+ /// Get the property information for all the properties declared in this class.
+ /// This method is used by Godot to register the available properties in the editor.
+ /// Do not call this method.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
+ internal new static global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo> GetGodotPropertyList()
+ {
+ var properties = new global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>();
+ return properties;
+ }
+#pragma warning restore CS0109
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedToolButtons_ScriptProperties.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedToolButtons_ScriptProperties.generated.cs
new file mode 100644
index 0000000000..6e4ad1f13e
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportedToolButtons_ScriptProperties.generated.cs
@@ -0,0 +1,48 @@
+using Godot;
+using Godot.NativeInterop;
+
+partial class ExportedToolButtons
+{
+#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword
+ /// <summary>
+ /// Cached StringNames for the properties and fields contained in this class, for fast lookup.
+ /// </summary>
+ public new class PropertyName : global::Godot.GodotObject.PropertyName {
+ /// <summary>
+ /// Cached name for the 'MyButton1' property.
+ /// </summary>
+ public new static readonly global::Godot.StringName @MyButton1 = "MyButton1";
+ /// <summary>
+ /// Cached name for the 'MyButton2' property.
+ /// </summary>
+ public new static readonly global::Godot.StringName @MyButton2 = "MyButton2";
+ }
+ /// <inheritdoc/>
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
+ protected override bool GetGodotClassPropertyValue(in godot_string_name name, out godot_variant value)
+ {
+ if (name == PropertyName.@MyButton1) {
+ value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Callable>(this.@MyButton1);
+ return true;
+ }
+ if (name == PropertyName.@MyButton2) {
+ value = global::Godot.NativeInterop.VariantUtils.CreateFrom<global::Godot.Callable>(this.@MyButton2);
+ return true;
+ }
+ return base.GetGodotClassPropertyValue(name, out value);
+ }
+ /// <summary>
+ /// Get the property information for all the properties declared in this class.
+ /// This method is used by Godot to register the available properties in the editor.
+ /// Do not call this method.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
+ internal new static global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo> GetGodotPropertyList()
+ {
+ var properties = new global::System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>();
+ properties.Add(new(type: (global::Godot.Variant.Type)25, name: PropertyName.@MyButton1, hint: (global::Godot.PropertyHint)39, hintString: "Click me!", usage: (global::Godot.PropertyUsageFlags)4, exported: true));
+ properties.Add(new(type: (global::Godot.Variant.Type)25, name: PropertyName.@MyButton2, hint: (global::Godot.PropertyHint)39, hintString: "Click me!,ColorRect", usage: (global::Godot.PropertyUsageFlags)4, exported: true));
+ return properties;
+ }
+#pragma warning restore CS0109
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0108.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0108.cs
new file mode 100644
index 0000000000..6fde2e5957
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0108.cs
@@ -0,0 +1,8 @@
+using Godot;
+using Godot.Collections;
+
+public partial class ExportDiagnostics_GD0108 : Node
+{
+ [ExportToolButton("")]
+ public Callable {|GD0108:MyButton|};
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0109.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0109.cs
new file mode 100644
index 0000000000..80a04cd641
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0109.cs
@@ -0,0 +1,9 @@
+using Godot;
+using Godot.Collections;
+
+[Tool]
+public partial class ExportDiagnostics_GD0109 : Node
+{
+ [Export, ExportToolButton("")]
+ public Callable {|GD0109:MyButton|};
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0110.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0110.cs
new file mode 100644
index 0000000000..586bf6c19e
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0110.cs
@@ -0,0 +1,9 @@
+using Godot;
+using Godot.Collections;
+
+[Tool]
+public partial class ExportDiagnostics_GD0110 : Node
+{
+ [ExportToolButton("")]
+ public string {|GD0110:MyButton|};
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedToolButtons.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedToolButtons.cs
new file mode 100644
index 0000000000..91c14387c5
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportedToolButtons.cs
@@ -0,0 +1,12 @@
+using Godot;
+using System;
+
+[Tool]
+public partial class ExportedToolButtons : GodotObject
+{
+ [ExportToolButton("Click me!")]
+ public Callable MyButton1 => Callable.From(() => { GD.Print("Clicked MyButton1!"); });
+
+ [ExportToolButton("Click me!", Icon = "ColorRect")]
+ public Callable MyButton2 => Callable.From(() => { GD.Print("Clicked MyButton2!"); });
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/AnalyzerReleases.Unshipped.md b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/AnalyzerReleases.Unshipped.md
index 7286853f7a..90c8491177 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/AnalyzerReleases.Unshipped.md
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/AnalyzerReleases.Unshipped.md
@@ -3,3 +3,6 @@
Rule ID | Category | Severity | Notes
--------|----------|----------|--------------------
GD0003 | Usage | Error | ScriptPathAttributeGenerator, [Documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/c_sharp/diagnostics/GD0003.html)
+GD0108 | Usage | Error | ScriptPropertiesGenerator, [Documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/c_sharp/diagnostics/GD0108.html)
+GD0109 | Usage | Error | ScriptPropertiesGenerator, [Documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/c_sharp/diagnostics/GD0109.html)
+GD0110 | Usage | Error | ScriptPropertiesGenerator, [Documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/c_sharp/diagnostics/GD0110.html)
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
index ad7962e7df..8da0818e42 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
@@ -107,6 +107,36 @@ namespace Godot.SourceGenerators
"Types not derived from Node should not export Node members. Node export is only supported in Node-derived classes.",
helpLinkUri: string.Format(_helpLinkFormat, "GD0107"));
+ public static readonly DiagnosticDescriptor OnlyToolClassesShouldUseExportToolButtonRule =
+ new DiagnosticDescriptor(id: "GD0108",
+ title: "The exported tool button is not in a tool class",
+ messageFormat: "The exported tool button '{0}' is not in a tool class",
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ "The exported tool button is not in a tool class. Annotate the class with the '[Tool]' attribute, or remove the '[ExportToolButton]' attribute.",
+ helpLinkUri: string.Format(_helpLinkFormat, "GD0108"));
+
+ public static readonly DiagnosticDescriptor ExportToolButtonShouldNotBeUsedWithExportRule =
+ new DiagnosticDescriptor(id: "GD0109",
+ title: "The '[ExportToolButton]' attribute cannot be used with another '[Export]' attribute",
+ messageFormat: "The '[ExportToolButton]' attribute cannot be used with another '[Export]' attribute on '{0}'",
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ "The '[ExportToolButton]' attribute cannot be used with the '[Export]' attribute. Remove one of the attributes.",
+ helpLinkUri: string.Format(_helpLinkFormat, "GD0109"));
+
+ public static readonly DiagnosticDescriptor ExportToolButtonIsNotCallableRule =
+ new DiagnosticDescriptor(id: "GD0110",
+ title: "The exported tool button is not a Callable",
+ messageFormat: "The exported tool button '{0}' is not a Callable",
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ "The exported tool button is not a Callable. The '[ExportToolButton]' attribute is only supported on members of type Callable.",
+ helpLinkUri: string.Format(_helpLinkFormat, "GD0110"));
+
public static readonly DiagnosticDescriptor SignalDelegateMissingSuffixRule =
new DiagnosticDescriptor(id: "GD0201",
title: "The name of the delegate must end with 'EventHandler'",
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
index 62fa7b0a36..46c446169a 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
@@ -287,6 +287,12 @@ namespace Godot.SourceGenerators
public static bool IsGodotGlobalClassAttribute(this INamedTypeSymbol symbol)
=> symbol.FullQualifiedNameOmitGlobal() == GodotClasses.GlobalClassAttr;
+ public static bool IsGodotExportToolButtonAttribute(this INamedTypeSymbol symbol)
+ => symbol.FullQualifiedNameOmitGlobal() == GodotClasses.ExportToolButtonAttr;
+
+ public static bool IsGodotToolAttribute(this INamedTypeSymbol symbol)
+ => symbol.FullQualifiedNameOmitGlobal() == GodotClasses.ToolAttr;
+
public static bool IsSystemFlagsAttribute(this INamedTypeSymbol symbol)
=> symbol.FullQualifiedNameOmitGlobal() == GodotClasses.SystemFlagsAttr;
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs
index af39a54b0b..f6de09e25b 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs
@@ -9,10 +9,12 @@ namespace Godot.SourceGenerators
public const string ExportCategoryAttr = "Godot.ExportCategoryAttribute";
public const string ExportGroupAttr = "Godot.ExportGroupAttribute";
public const string ExportSubgroupAttr = "Godot.ExportSubgroupAttribute";
+ public const string ExportToolButtonAttr = "Godot.ExportToolButtonAttribute";
public const string SignalAttr = "Godot.SignalAttribute";
public const string MustBeVariantAttr = "Godot.MustBeVariantAttribute";
public const string GodotClassNameAttr = "Godot.GodotClassNameAttribute";
public const string GlobalClassAttr = "Godot.GlobalClassAttribute";
+ public const string ToolAttr = "Godot.ToolAttribute";
public const string SystemFlagsAttr = "System.FlagsAttribute";
}
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs
index bb4c4824e7..d77ebc3cec 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs
@@ -89,7 +89,8 @@ namespace Godot.SourceGenerators
Password = 36,
LayersAvoidance = 37,
DictionaryType = 38,
- Max = 39
+ ToolButton = 39,
+ Max = 40
}
[Flags]
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
index fc67e4f592..a8033914e7 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
@@ -69,6 +69,7 @@ namespace Godot.SourceGenerators
bool hasNamespace = classNs.Length != 0;
bool isInnerClass = symbol.ContainingType != null;
+ bool isToolClass = symbol.GetAttributes().Any(a => a.AttributeClass?.IsGodotToolAttribute() ?? false);
string uniqueHint = symbol.FullQualifiedNameOmitGlobal().SanitizeQualifiedNameForUniqueHint()
+ "_ScriptProperties.generated";
@@ -277,6 +278,16 @@ namespace Godot.SourceGenerators
if (propertyInfo == null)
continue;
+ if (propertyInfo.Value.Hint == PropertyHint.ToolButton && !isToolClass)
+ {
+ context.ReportDiagnostic(Diagnostic.Create(
+ Common.OnlyToolClassesShouldUseExportToolButtonRule,
+ member.Symbol.Locations.FirstLocationWithSourceTreeOrDefault(),
+ member.Symbol.ToDisplayString()
+ ));
+ continue;
+ }
+
AppendPropertyInfo(source, propertyInfo.Value);
}
@@ -418,47 +429,82 @@ namespace Godot.SourceGenerators
var exportAttr = memberSymbol.GetAttributes()
.FirstOrDefault(a => a.AttributeClass?.IsGodotExportAttribute() ?? false);
+ var exportToolButtonAttr = memberSymbol.GetAttributes()
+ .FirstOrDefault(a => a.AttributeClass?.IsGodotExportToolButtonAttribute() ?? false);
+
+ if (exportAttr != null && exportToolButtonAttr != null)
+ {
+ context.ReportDiagnostic(Diagnostic.Create(
+ Common.ExportToolButtonShouldNotBeUsedWithExportRule,
+ memberSymbol.Locations.FirstLocationWithSourceTreeOrDefault(),
+ memberSymbol.ToDisplayString()
+ ));
+ return null;
+ }
+
var propertySymbol = memberSymbol as IPropertySymbol;
var fieldSymbol = memberSymbol as IFieldSymbol;
if (exportAttr != null && propertySymbol != null)
{
- if (propertySymbol.GetMethod == null)
+ if (propertySymbol.GetMethod == null || propertySymbol.SetMethod == null || propertySymbol.SetMethod.IsInitOnly)
{
- // This should never happen, as we filtered WriteOnly properties, but just in case.
- context.ReportDiagnostic(Diagnostic.Create(
- Common.ExportedPropertyIsWriteOnlyRule,
- propertySymbol.Locations.FirstLocationWithSourceTreeOrDefault(),
- propertySymbol.ToDisplayString()
- ));
+ // Exports can be neither read-only nor write-only but the diagnostic errors for properties are already
+ // reported by ScriptPropertyDefValGenerator.cs so just quit early here.
return null;
}
+ }
+
+ if (exportToolButtonAttr != null && propertySymbol != null && propertySymbol.GetMethod == null)
+ {
+ context.ReportDiagnostic(Diagnostic.Create(
+ Common.ExportedPropertyIsWriteOnlyRule,
+ propertySymbol.Locations.FirstLocationWithSourceTreeOrDefault(),
+ propertySymbol.ToDisplayString()
+ ));
+ return null;
+ }
- if (propertySymbol.SetMethod == null || propertySymbol.SetMethod.IsInitOnly)
+ var memberType = propertySymbol?.Type ?? fieldSymbol!.Type;
+
+ var memberVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(marshalType)!.Value;
+ string memberName = memberSymbol.Name;
+
+ string? hintString = null;
+
+ if (exportToolButtonAttr != null)
+ {
+ if (memberVariantType != VariantType.Callable)
{
- // This should never happen, as we filtered ReadOnly properties, but just in case.
context.ReportDiagnostic(Diagnostic.Create(
- Common.ExportedMemberIsReadOnlyRule,
- propertySymbol.Locations.FirstLocationWithSourceTreeOrDefault(),
- propertySymbol.ToDisplayString()
+ Common.ExportToolButtonIsNotCallableRule,
+ memberSymbol.Locations.FirstLocationWithSourceTreeOrDefault(),
+ memberSymbol.ToDisplayString()
));
return null;
}
- }
- var memberType = propertySymbol?.Type ?? fieldSymbol!.Type;
+ hintString = exportToolButtonAttr.ConstructorArguments[0].Value?.ToString() ?? "";
+ foreach (var namedArgument in exportToolButtonAttr.NamedArguments)
+ {
+ if (namedArgument is { Key: "Icon", Value.Value: string { Length: > 0 } })
+ {
+ hintString += $",{namedArgument.Value.Value}";
+ }
+ }
- var memberVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(marshalType)!.Value;
- string memberName = memberSymbol.Name;
+ return new PropertyInfo(memberVariantType, memberName, PropertyHint.ToolButton,
+ hintString: hintString, PropertyUsageFlags.Editor, exported: true);
+ }
if (exportAttr == null)
{
return new PropertyInfo(memberVariantType, memberName, PropertyHint.None,
- hintString: null, PropertyUsageFlags.ScriptVariable, exported: false);
+ hintString: hintString, PropertyUsageFlags.ScriptVariable, exported: false);
}
if (!TryGetMemberExportHint(typeCache, memberType, exportAttr, memberVariantType,
- isTypeArgument: false, out var hint, out var hintString))
+ isTypeArgument: false, out var hint, out hintString))
{
var constructorArguments = exportAttr.ConstructorArguments;
@@ -735,8 +781,18 @@ namespace Godot.SourceGenerators
return false; // Non-generic Dictionary, so there's no hint to add
Debug.Assert(elementTypes.Length == 2);
- var keyElementMarshalType = MarshalUtils.ConvertManagedTypeToMarshalType(elementTypes[0], typeCache)!.Value;
- var keyElementVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(keyElementMarshalType)!.Value;
+ var keyElementMarshalType = MarshalUtils.ConvertManagedTypeToMarshalType(elementTypes[0], typeCache);
+ var valueElementMarshalType = MarshalUtils.ConvertManagedTypeToMarshalType(elementTypes[1], typeCache);
+
+ if (keyElementMarshalType == null || valueElementMarshalType == null)
+ {
+ // To maintain compatibility with previous versions of Godot before 4.4,
+ // we must preserve the old behavior for generic dictionaries with non-marshallable
+ // generic type arguments.
+ return false;
+ }
+
+ var keyElementVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(keyElementMarshalType.Value)!.Value;
var keyIsPresetHint = false;
var keyHintString = (string?)null;
@@ -763,8 +819,7 @@ namespace Godot.SourceGenerators
}
}
- var valueElementMarshalType = MarshalUtils.ConvertManagedTypeToMarshalType(elementTypes[1], typeCache)!.Value;
- var valueElementVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(valueElementMarshalType)!.Value;
+ var valueElementVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(valueElementMarshalType.Value)!.Value;
var valueIsPresetHint = false;
var valueHintString = (string?)null;
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
index 702c50d461..c7a7415851 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
@@ -295,7 +295,7 @@ namespace Godot.SourceGenerators
for (int i = 0; i < paramCount; i++)
{
var paramSymbol = invokeMethodSymbol.Parameters[i];
- source.Append($"{paramSymbol.Type.FullQualifiedNameIncludeGlobal()} {paramSymbol.Name}");
+ source.Append($"{paramSymbol.Type.FullQualifiedNameIncludeGlobal()} @{paramSymbol.Name}");
if (i < paramCount - 1)
{
source.Append(", ");
@@ -310,11 +310,11 @@ namespace Godot.SourceGenerators
if (paramSymbol.Type.TypeKind == TypeKind.Enum)
{
var underlyingType = ((INamedTypeSymbol)paramSymbol.Type).EnumUnderlyingType;
- source.Append($", ({underlyingType.FullQualifiedNameIncludeGlobal()}){paramSymbol.Name}");
+ source.Append($", ({underlyingType.FullQualifiedNameIncludeGlobal()})@{paramSymbol.Name}");
continue;
}
- source.Append($", {paramSymbol.Name}");
+ source.Append($", @{paramSymbol.Name}");
}
source.Append(");\n");
source.Append(" }\n");
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index db90ac5a6e..d0797282de 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -190,7 +190,7 @@ String BindingsGenerator::bbcode_to_text(const String &p_bbcode, const TypeInter
int pos = 0;
while (pos < bbcode.length()) {
- int brk_pos = bbcode.find("[", pos);
+ int brk_pos = bbcode.find_char('[', pos);
if (brk_pos < 0) {
brk_pos = bbcode.length();
@@ -210,7 +210,7 @@ String BindingsGenerator::bbcode_to_text(const String &p_bbcode, const TypeInter
break;
}
- int brk_end = bbcode.find("]", brk_pos + 1);
+ int brk_end = bbcode.find_char(']', brk_pos + 1);
if (brk_end == -1) {
String text = bbcode.substr(brk_pos, bbcode.length() - brk_pos);
@@ -239,7 +239,7 @@ String BindingsGenerator::bbcode_to_text(const String &p_bbcode, const TypeInter
output.append("[");
pos = brk_pos + 1;
} else if (tag.begins_with("method ") || tag.begins_with("constructor ") || tag.begins_with("operator ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ") || tag.begins_with("constant ") || tag.begins_with("theme_item ") || tag.begins_with("param ")) {
- const int tag_end = tag.find(" ");
+ const int tag_end = tag.find_char(' ');
const String link_tag = tag.substr(0, tag_end);
const String link_target = tag.substr(tag_end + 1, tag.length()).lstrip(" ");
@@ -385,7 +385,7 @@ String BindingsGenerator::bbcode_to_text(const String &p_bbcode, const TypeInter
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "url") {
- int end = bbcode.find("[", brk_end);
+ int end = bbcode.find_char('[', brk_end);
if (end == -1) {
end = bbcode.length();
}
@@ -403,7 +403,7 @@ String BindingsGenerator::bbcode_to_text(const String &p_bbcode, const TypeInter
pos = brk_end + 1;
tag_stack.push_front("url");
} else if (tag == "img") {
- int end = bbcode.find("[", brk_end);
+ int end = bbcode.find_char('[', brk_end);
if (end == -1) {
end = bbcode.length();
}
@@ -455,7 +455,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
int pos = 0;
while (pos < bbcode.length()) {
- int brk_pos = bbcode.find("[", pos);
+ int brk_pos = bbcode.find_char('[', pos);
if (brk_pos < 0) {
brk_pos = bbcode.length();
@@ -488,7 +488,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
break;
}
- int brk_end = bbcode.find("]", brk_pos + 1);
+ int brk_end = bbcode.find_char(']', brk_pos + 1);
if (brk_end == -1) {
if (!line_del) {
@@ -551,7 +551,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
xml_output.append("[");
pos = brk_pos + 1;
} else if (tag.begins_with("method ") || tag.begins_with("constructor ") || tag.begins_with("operator ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ") || tag.begins_with("constant ") || tag.begins_with("theme_item ") || tag.begins_with("param ")) {
- const int tag_end = tag.find(" ");
+ const int tag_end = tag.find_char(' ');
const String link_tag = tag.substr(0, tag_end);
const String link_target = tag.substr(tag_end + 1, tag.length()).lstrip(" ");
@@ -696,7 +696,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "code" || tag.begins_with("code ")) {
- int end = bbcode.find("[", brk_end);
+ int end = bbcode.find_char('[', brk_end);
if (end == -1) {
end = bbcode.length();
}
@@ -751,7 +751,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "url") {
- int end = bbcode.find("[", brk_end);
+ int end = bbcode.find_char('[', brk_end);
if (end == -1) {
end = bbcode.length();
}
@@ -772,7 +772,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
pos = brk_end + 1;
tag_stack.push_front("url");
} else if (tag == "img") {
- int end = bbcode.find("[", brk_end);
+ int end = bbcode.find_char('[', brk_end);
if (end == -1) {
end = bbcode.length();
}
@@ -1619,7 +1619,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
bool enum_in_static_class = false;
- if (enum_proxy_name.find(".") > 0) {
+ if (enum_proxy_name.find_char('.') > 0) {
enum_in_static_class = true;
String enum_class_name = enum_proxy_name.get_slicec('.', 0);
enum_proxy_name = enum_proxy_name.get_slicec('.', 1);
@@ -5040,22 +5040,25 @@ void BindingsGenerator::_populate_global_constants() {
}
}
- // HARDCODED
- List<StringName> hardcoded_enums;
- hardcoded_enums.push_back("Vector2.Axis");
- hardcoded_enums.push_back("Vector2I.Axis");
- hardcoded_enums.push_back("Vector3.Axis");
- hardcoded_enums.push_back("Vector3I.Axis");
- for (const StringName &enum_cname : hardcoded_enums) {
- // These enums are not generated and must be written manually (e.g.: Vector3.Axis)
- // Here, we assume core types do not begin with underscore
- TypeInterface enum_itype;
- enum_itype.is_enum = true;
- enum_itype.name = enum_cname.operator String();
- enum_itype.cname = enum_cname;
- enum_itype.proxy_name = pascal_to_pascal_case(enum_itype.name);
- TypeInterface::postsetup_enum_type(enum_itype);
- enum_types.insert(enum_itype.cname, enum_itype);
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ if (i == Variant::OBJECT) {
+ continue;
+ }
+
+ const Variant::Type type = Variant::Type(i);
+
+ List<StringName> enum_names;
+ Variant::get_enums_for_type(type, &enum_names);
+
+ for (const StringName &enum_name : enum_names) {
+ TypeInterface enum_itype;
+ enum_itype.is_enum = true;
+ enum_itype.name = Variant::get_type_name(type) + "." + enum_name;
+ enum_itype.cname = enum_itype.name;
+ enum_itype.proxy_name = pascal_to_pascal_case(enum_itype.name);
+ TypeInterface::postsetup_enum_type(enum_itype);
+ enum_types.insert(enum_itype.cname, enum_itype);
+ }
}
}
diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp
index ae914e71ef..94222f3d67 100644
--- a/modules/mono/editor/code_completion.cpp
+++ b/modules/mono/editor/code_completion.cpp
@@ -116,7 +116,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
continue;
}
- String name = prop.name.substr(prop.name.find("/") + 1, prop.name.length());
+ String name = prop.name.substr(prop.name.find_char('/') + 1, prop.name.length());
suggestions.push_back(quoted(name));
}
} break;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportToolButtonAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportToolButtonAttribute.cs
new file mode 100644
index 0000000000..87a9e628f9
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportToolButtonAttribute.cs
@@ -0,0 +1,33 @@
+using System;
+
+#nullable enable
+
+namespace Godot
+{
+ /// <summary>
+ /// Exports the annotated <see cref="Callable"/> as a clickable button.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ public sealed class ExportToolButtonAttribute : Attribute
+ {
+ /// <summary>
+ /// The label of the button.
+ /// </summary>
+ public string Text { get; }
+
+ /// <summary>
+ /// If defined, used to fetch an icon for the button via <see cref="Control.GetThemeIcon"/>,
+ /// from the <code>EditorIcons</code> theme type.
+ /// </summary>
+ public string? Icon { get; init; }
+
+ /// <summary>
+ /// Exports the annotated <see cref="Callable"/> as a clickable button.
+ /// </summary>
+ /// <param name="text">The label of the button.</param>
+ public ExportToolButtonAttribute(string text)
+ {
+ Text = text;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
index dc151e2c3e..222ded6895 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
@@ -534,7 +534,10 @@ namespace Godot.NativeInterop
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Callable ConvertToCallable(in godot_variant p_var)
- => Marshaling.ConvertCallableToManaged(ConvertToNativeCallable(p_var));
+ {
+ using var callable = ConvertToNativeCallable(p_var);
+ return Marshaling.ConvertCallableToManaged(callable);
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static godot_signal ConvertToNativeSignal(in godot_variant p_var)
@@ -542,7 +545,10 @@ namespace Godot.NativeInterop
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Signal ConvertToSignal(in godot_variant p_var)
- => Marshaling.ConvertSignalToManaged(ConvertToNativeSignal(p_var));
+ {
+ using var signal = ConvertToNativeSignal(p_var);
+ return Marshaling.ConvertSignalToManaged(signal);
+ }
public static godot_array ConvertToNativeArray(in godot_variant p_var)
=> p_var.Type == Variant.Type.Array ?
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index 3a3134d160..5aa68559d8 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -48,6 +48,7 @@
<!-- Sources -->
<ItemGroup>
<Compile Include="Core\Aabb.cs" />
+ <Compile Include="Core\Attributes\ExportToolButtonAttribute.cs" />
<Compile Include="Core\Bridge\GodotSerializationInfo.cs" />
<Compile Include="Core\Bridge\MethodInfo.cs" />
<Compile Include="Core\Callable.generics.cs" />
diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp
index ee17a668d7..068ac8b4e1 100644
--- a/modules/mono/utils/path_utils.cpp
+++ b/modules/mono/utils/path_utils.cpp
@@ -212,7 +212,7 @@ String relative_to_impl(const String &p_path, const String &p_relative_to) {
#ifdef WINDOWS_ENABLED
String get_drive_letter(const String &p_norm_path) {
int idx = p_norm_path.find(":/");
- if (idx != -1 && idx < p_norm_path.find("/")) {
+ if (idx != -1 && idx < p_norm_path.find_char('/')) {
return p_norm_path.substr(0, idx + 1);
}
return String();
diff --git a/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml b/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml
index c2d879962c..edcaa3baef 100644
--- a/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml
+++ b/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml
@@ -53,7 +53,7 @@
</methods>
<members>
<member name="delta_interval" type="float" setter="set_delta_interval" getter="get_delta_interval" default="0.0">
- Time interval between delta synchronizations. When set to [code]0.0[/code] (the default), delta synchronizations happen every network process frame.
+ Time interval between delta synchronizations. Used when the replication is set to [constant SceneReplicationConfig.REPLICATION_MODE_ON_CHANGE]. If set to [code]0.0[/code] (the default), delta synchronizations happen every network process frame.
</member>
<member name="public_visibility" type="bool" setter="set_visibility_public" getter="is_visibility_public" default="true">
Whether synchronization should be visible to all peers by default. See [method set_visibility_for] and [method add_visibility_filter] for ways of configuring fine-grained visibility options.
@@ -62,7 +62,7 @@
Resource containing which properties to synchronize.
</member>
<member name="replication_interval" type="float" setter="set_replication_interval" getter="get_replication_interval" default="0.0">
- Time interval between synchronizations. When set to [code]0.0[/code] (the default), synchronizations happen every network process frame.
+ Time interval between synchronizations. Used when the replication is set to [constant SceneReplicationConfig.REPLICATION_MODE_ALWAYS]. If set to [code]0.0[/code] (the default), synchronizations happen every network process frame.
</member>
<member name="root_path" type="NodePath" setter="set_root_path" getter="get_root_path" default="NodePath(&quot;..&quot;)">
Node path that replicated properties are relative to.
diff --git a/modules/multiplayer/editor/replication_editor.cpp b/modules/multiplayer/editor/replication_editor.cpp
index 8de82ef409..4d5480eebf 100644
--- a/modules/multiplayer/editor/replication_editor.cpp
+++ b/modules/multiplayer/editor/replication_editor.cpp
@@ -375,7 +375,7 @@ void ReplicationEditor::_add_pressed() {
return;
}
- int idx = np_text.find(":");
+ int idx = np_text.find_char(':');
if (idx == -1) {
np_text = ".:" + np_text;
} else if (idx == 0) {
@@ -554,7 +554,7 @@ void ReplicationEditor::_add_property(const NodePath &p_property, bool p_spawn,
Node *root_node = current && !current->get_root_path().is_empty() ? current->get_node(current->get_root_path()) : nullptr;
Ref<Texture2D> icon = _get_class_icon(root_node);
if (root_node) {
- String path = prop.substr(0, prop.find(":"));
+ String path = prop.substr(0, prop.find_char(':'));
String subpath = prop.substr(path.size());
Node *node = root_node->get_node_or_null(path);
if (!node) {
diff --git a/modules/multiplayer/multiplayer_spawner.cpp b/modules/multiplayer/multiplayer_spawner.cpp
index 682d20022f..69a7545e51 100644
--- a/modules/multiplayer/multiplayer_spawner.cpp
+++ b/modules/multiplayer/multiplayer_spawner.cpp
@@ -97,7 +97,13 @@ PackedStringArray MultiplayerSpawner::get_configuration_warnings() const {
void MultiplayerSpawner::add_spawnable_scene(const String &p_path) {
SpawnableScene sc;
- sc.path = p_path;
+ if (p_path.begins_with("uid://")) {
+ sc.uid = p_path;
+ sc.path = ResourceUID::uid_to_path(p_path);
+ } else {
+ sc.uid = ResourceUID::path_to_uid(p_path);
+ sc.path = p_path;
+ }
if (Engine::get_singleton()->is_editor_hint()) {
ERR_FAIL_COND(!ResourceLoader::exists(p_path));
}
@@ -139,7 +145,7 @@ Vector<String> MultiplayerSpawner::_get_spawnable_scenes() const {
Vector<String> ss;
ss.resize(spawnable_scenes.size());
for (int i = 0; i < ss.size(); i++) {
- ss.write[i] = spawnable_scenes[i].path;
+ ss.write[i] = spawnable_scenes[i].uid;
}
return ss;
}
diff --git a/modules/multiplayer/multiplayer_spawner.h b/modules/multiplayer/multiplayer_spawner.h
index 0e94b781ea..868efb9e0b 100644
--- a/modules/multiplayer/multiplayer_spawner.h
+++ b/modules/multiplayer/multiplayer_spawner.h
@@ -49,6 +49,7 @@ public:
private:
struct SpawnableScene {
String path;
+ String uid;
Ref<PackedScene> cache;
};
diff --git a/modules/navigation/2d/nav_mesh_generator_2d.cpp b/modules/navigation/2d/nav_mesh_generator_2d.cpp
index 2339936ec4..a8eb07147c 100644
--- a/modules/navigation/2d/nav_mesh_generator_2d.cpp
+++ b/modules/navigation/2d/nav_mesh_generator_2d.cpp
@@ -691,11 +691,15 @@ void NavMeshGenerator2D::generator_parse_navigationobstacle_node(const Ref<Navig
return;
}
- const Transform2D node_xform = p_source_geometry_data->root_node_transform * Transform2D(0.0, obstacle->get_global_position());
-
+ const Vector2 safe_scale = obstacle->get_global_scale().abs().maxf(0.001);
const float obstacle_radius = obstacle->get_radius();
if (obstacle_radius > 0.0) {
+ // Radius defined obstacle should be uniformly scaled from obstacle basis max scale axis.
+ const float scaling_max_value = safe_scale[safe_scale.max_axis_index()];
+ const Vector2 uniform_max_scale = Vector2(scaling_max_value, scaling_max_value);
+ const Transform2D obstacle_circle_transform = p_source_geometry_data->root_node_transform * Transform2D(obstacle->get_global_rotation(), uniform_max_scale, 0.0, obstacle->get_global_position());
+
Vector<Vector2> obstruction_circle_vertices;
// The point of this is that the moving obstacle can make a simple hole in the navigation mesh and affect the pathfinding.
@@ -709,12 +713,15 @@ void NavMeshGenerator2D::generator_parse_navigationobstacle_node(const Ref<Navig
for (int i = 0; i < circle_points; i++) {
const float angle = i * circle_point_step;
- circle_vertices_ptrw[i] = node_xform.xform(Vector2(Math::cos(angle) * obstacle_radius, Math::sin(angle) * obstacle_radius));
+ circle_vertices_ptrw[i] = obstacle_circle_transform.xform(Vector2(Math::cos(angle) * obstacle_radius, Math::sin(angle) * obstacle_radius));
}
p_source_geometry_data->add_projected_obstruction(obstruction_circle_vertices, obstacle->get_carve_navigation_mesh());
}
+ // Obstacles are projected to the xz-plane, so only rotation around the y-axis can be taken into account.
+ const Transform2D node_xform = p_source_geometry_data->root_node_transform * obstacle->get_global_transform();
+
const Vector<Vector2> &obstacle_vertices = obstacle->get_vertices();
if (obstacle_vertices.is_empty()) {
@@ -843,7 +850,7 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref<Navigation
using namespace Clipper2Lib;
PathsD traversable_polygon_paths;
PathsD obstruction_polygon_paths;
- int obstruction_polygon_path_size = 0;
+ bool empty_projected_obstructions = true;
{
RWLockRead read_lock(p_source_geometry_data->geometry_rwlock);
@@ -879,7 +886,8 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref<Navigation
traversable_polygon_paths.push_back(std::move(subject_path));
}
- if (!projected_obstructions.is_empty()) {
+ empty_projected_obstructions = projected_obstructions.is_empty();
+ if (!empty_projected_obstructions) {
for (const NavigationMeshSourceGeometryData2D::ProjectedObstruction &projected_obstruction : projected_obstructions) {
if (projected_obstruction.carve) {
continue;
@@ -900,7 +908,6 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref<Navigation
}
}
- obstruction_polygon_path_size = obstruction_polygon_paths.size();
for (const Vector<Vector2> &obstruction_outline : obstruction_outlines) {
PathD clip_path;
clip_path.reserve(obstruction_outline.size());
@@ -912,7 +919,6 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref<Navigation
}
Rect2 baking_rect = p_navigation_mesh->get_baking_rect();
- PathsD area_obstruction_polygon_paths;
if (baking_rect.has_area()) {
Vector2 baking_rect_offset = p_navigation_mesh->get_baking_rect_offset();
@@ -924,27 +930,48 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref<Navigation
RectD clipper_rect = RectD(rect_begin_x, rect_begin_y, rect_end_x, rect_end_y);
traversable_polygon_paths = RectClip(clipper_rect, traversable_polygon_paths);
- area_obstruction_polygon_paths = RectClip(clipper_rect, obstruction_polygon_paths);
- } else {
- area_obstruction_polygon_paths = obstruction_polygon_paths;
+ obstruction_polygon_paths = RectClip(clipper_rect, obstruction_polygon_paths);
}
// first merge all traversable polygons according to user specified fill rule
PathsD dummy_clip_path;
traversable_polygon_paths = Union(traversable_polygon_paths, dummy_clip_path, FillRule::NonZero);
// merge all obstruction polygons, don't allow holes for what is considered "solid" 2D geometry
- area_obstruction_polygon_paths = Union(area_obstruction_polygon_paths, dummy_clip_path, FillRule::NonZero);
+ obstruction_polygon_paths = Union(obstruction_polygon_paths, dummy_clip_path, FillRule::NonZero);
- PathsD path_solution = Difference(traversable_polygon_paths, area_obstruction_polygon_paths, FillRule::NonZero);
+ PathsD path_solution = Difference(traversable_polygon_paths, obstruction_polygon_paths, FillRule::NonZero);
real_t agent_radius_offset = p_navigation_mesh->get_agent_radius();
if (agent_radius_offset > 0.0) {
path_solution = InflatePaths(path_solution, -agent_radius_offset, JoinType::Miter, EndType::Polygon);
}
- if (obstruction_polygon_path_size > 0) {
- obstruction_polygon_paths.resize(obstruction_polygon_path_size);
- path_solution = Difference(path_solution, obstruction_polygon_paths, FillRule::NonZero);
+ // Apply obstructions that are not affected by agent radius, the ones with carve enabled.
+ if (!empty_projected_obstructions) {
+ RWLockRead read_lock(p_source_geometry_data->geometry_rwlock);
+ const Vector<NavigationMeshSourceGeometryData2D::ProjectedObstruction> &projected_obstructions = p_source_geometry_data->_projected_obstructions;
+ obstruction_polygon_paths.resize(0);
+ for (const NavigationMeshSourceGeometryData2D::ProjectedObstruction &projected_obstruction : projected_obstructions) {
+ if (!projected_obstruction.carve) {
+ continue;
+ }
+ if (projected_obstruction.vertices.is_empty() || projected_obstruction.vertices.size() % 2 != 0) {
+ continue;
+ }
+
+ PathD clip_path;
+ clip_path.reserve(projected_obstruction.vertices.size() / 2);
+ for (int i = 0; i < projected_obstruction.vertices.size() / 2; i++) {
+ clip_path.emplace_back(projected_obstruction.vertices[i * 2], projected_obstruction.vertices[i * 2 + 1]);
+ }
+ if (!IsPositive(clip_path)) {
+ std::reverse(clip_path.begin(), clip_path.end());
+ }
+ obstruction_polygon_paths.push_back(std::move(clip_path));
+ }
+ if (obstruction_polygon_paths.size() > 0) {
+ path_solution = Difference(path_solution, obstruction_polygon_paths, FillRule::NonZero);
+ }
}
//path_solution = RamerDouglasPeucker(path_solution, 0.025); //
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index 8055dd4bc8..d7b5ab87c5 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -356,16 +356,10 @@ Vector3 NavMap::get_random_point(uint32_t p_navigation_layers, bool p_uniformly)
void NavMap::sync() {
RWLockWrite write_lock(map_rwlock);
- // Performance Monitor
- int _new_pm_region_count = regions.size();
- int _new_pm_agent_count = agents.size();
- int _new_pm_link_count = links.size();
- int _new_pm_polygon_count = pm_polygon_count;
- int _new_pm_edge_count = pm_edge_count;
- int _new_pm_edge_merge_count = pm_edge_merge_count;
- int _new_pm_edge_connection_count = pm_edge_connection_count;
- int _new_pm_edge_free_count = pm_edge_free_count;
- int _new_pm_obstacle_count = obstacles.size();
+ performance_data.pm_region_count = regions.size();
+ performance_data.pm_agent_count = agents.size();
+ performance_data.pm_link_count = links.size();
+ performance_data.pm_obstacle_count = obstacles.size();
// Check if we need to update the links.
if (regenerate_polygons) {
@@ -388,11 +382,11 @@ void NavMap::sync() {
}
if (regenerate_links) {
- _new_pm_polygon_count = 0;
- _new_pm_edge_count = 0;
- _new_pm_edge_merge_count = 0;
- _new_pm_edge_connection_count = 0;
- _new_pm_edge_free_count = 0;
+ performance_data.pm_polygon_count = 0;
+ performance_data.pm_edge_count = 0;
+ performance_data.pm_edge_merge_count = 0;
+ performance_data.pm_edge_connection_count = 0;
+ performance_data.pm_edge_free_count = 0;
// Remove regions connections.
region_external_connections.clear();
@@ -424,7 +418,7 @@ void NavMap::sync() {
}
}
- _new_pm_polygon_count = polygon_count;
+ performance_data.pm_polygon_count = polygon_count;
// Group all edges per key.
connection_pairs_map.clear();
@@ -439,7 +433,7 @@ void NavMap::sync() {
HashMap<gd::EdgeKey, ConnectionPair, gd::EdgeKey>::Iterator pair_it = connection_pairs_map.find(ek);
if (!pair_it) {
pair_it = connection_pairs_map.insert(ek, ConnectionPair());
- _new_pm_edge_count += 1;
+ performance_data.pm_edge_count += 1;
++free_edges_count;
}
ConnectionPair &pair = pair_it->value;
@@ -476,7 +470,7 @@ void NavMap::sync() {
c1.polygon->edges[c1.edge].connections.push_back(c2);
c2.polygon->edges[c2.edge].connections.push_back(c1);
// Note: The pathway_start/end are full for those connection and do not need to be modified.
- _new_pm_edge_merge_count += 1;
+ performance_data.pm_edge_merge_count += 1;
} else {
CRASH_COND_MSG(pair.size != 1, vformat("Number of connection != 1. Found: %d", pair.size));
if (use_edge_connections && pair.connections[0].polygon->owner->get_use_edge_connections()) {
@@ -492,7 +486,7 @@ void NavMap::sync() {
// to be connected, create new polygons to remove that small gap is
// not really useful and would result in wasteful computation during
// connection, integration and path finding.
- _new_pm_edge_free_count = free_edges.size();
+ performance_data.pm_edge_free_count = free_edges.size();
const real_t edge_connection_margin_squared = edge_connection_margin * edge_connection_margin;
@@ -549,7 +543,7 @@ void NavMap::sync() {
// Add the connection to the region_connection map.
region_external_connections[(NavRegion *)free_edge.polygon->owner].push_back(new_connection);
- _new_pm_edge_connection_count += 1;
+ performance_data.pm_edge_connection_count += 1;
}
}
@@ -687,17 +681,6 @@ void NavMap::sync() {
regenerate_links = false;
obstacles_dirty = false;
agents_dirty = false;
-
- // Performance Monitor.
- pm_region_count = _new_pm_region_count;
- pm_agent_count = _new_pm_agent_count;
- pm_link_count = _new_pm_link_count;
- pm_polygon_count = _new_pm_polygon_count;
- pm_edge_count = _new_pm_edge_count;
- pm_edge_merge_count = _new_pm_edge_merge_count;
- pm_edge_connection_count = _new_pm_edge_connection_count;
- pm_edge_free_count = _new_pm_edge_free_count;
- pm_obstacle_count = _new_pm_obstacle_count;
}
void NavMap::_update_rvo_obstacles_tree_2d() {
diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h
index 3442b78497..7eaf2133b9 100644
--- a/modules/navigation/nav_map.h
+++ b/modules/navigation/nav_map.h
@@ -116,15 +116,7 @@ class NavMap : public NavRid {
bool avoidance_use_high_priority_threads = true;
// Performance Monitor
- int pm_region_count = 0;
- int pm_agent_count = 0;
- int pm_link_count = 0;
- int pm_polygon_count = 0;
- int pm_edge_count = 0;
- int pm_edge_merge_count = 0;
- int pm_edge_connection_count = 0;
- int pm_edge_free_count = 0;
- int pm_obstacle_count = 0;
+ gd::PerformanceData performance_data;
HashMap<NavRegion *, LocalVector<gd::Edge::Connection>> region_external_connections;
@@ -220,15 +212,15 @@ public:
void dispatch_callbacks();
// Performance Monitor
- int get_pm_region_count() const { return pm_region_count; }
- int get_pm_agent_count() const { return pm_agent_count; }
- int get_pm_link_count() const { return pm_link_count; }
- int get_pm_polygon_count() const { return pm_polygon_count; }
- int get_pm_edge_count() const { return pm_edge_count; }
- int get_pm_edge_merge_count() const { return pm_edge_merge_count; }
- int get_pm_edge_connection_count() const { return pm_edge_connection_count; }
- int get_pm_edge_free_count() const { return pm_edge_free_count; }
- int get_pm_obstacle_count() const { return pm_obstacle_count; }
+ int get_pm_region_count() const { return performance_data.pm_region_count; }
+ int get_pm_agent_count() const { return performance_data.pm_agent_count; }
+ int get_pm_link_count() const { return performance_data.pm_link_count; }
+ int get_pm_polygon_count() const { return performance_data.pm_polygon_count; }
+ int get_pm_edge_count() const { return performance_data.pm_edge_count; }
+ int get_pm_edge_merge_count() const { return performance_data.pm_edge_merge_count; }
+ int get_pm_edge_connection_count() const { return performance_data.pm_edge_connection_count; }
+ int get_pm_edge_free_count() const { return performance_data.pm_edge_free_count; }
+ int get_pm_obstacle_count() const { return performance_data.pm_obstacle_count; }
int get_region_connections_count(NavRegion *p_region) const;
Vector3 get_region_connection_pathway_start(NavRegion *p_region, int p_connection_id) const;
diff --git a/modules/navigation/nav_utils.h b/modules/navigation/nav_utils.h
index c466c82fc7..993a97638d 100644
--- a/modules/navigation/nav_utils.h
+++ b/modules/navigation/nav_utils.h
@@ -298,6 +298,19 @@ private:
}
}
};
+
+struct PerformanceData {
+ int pm_region_count = 0;
+ int pm_agent_count = 0;
+ int pm_link_count = 0;
+ int pm_polygon_count = 0;
+ int pm_edge_count = 0;
+ int pm_edge_merge_count = 0;
+ int pm_edge_connection_count = 0;
+ int pm_edge_free_count = 0;
+ int pm_obstacle_count = 0;
+};
+
} // namespace gd
#endif // NAV_UTILS_H
diff --git a/modules/noise/doc_classes/FastNoiseLite.xml b/modules/noise/doc_classes/FastNoiseLite.xml
index 6f6a637893..e29581693b 100644
--- a/modules/noise/doc_classes/FastNoiseLite.xml
+++ b/modules/noise/doc_classes/FastNoiseLite.xml
@@ -118,7 +118,7 @@
Manhattan distance (taxicab metric) to the nearest point.
</constant>
<constant name="DISTANCE_HYBRID" value="3" enum="CellularDistanceFunction">
- Blend of [constant DISTANCE_EUCLIDEAN] and [constant DISTANCE_MANHATTAN] to give curved cell boundaries
+ Blend of [constant DISTANCE_EUCLIDEAN] and [constant DISTANCE_MANHATTAN] to give curved cell boundaries.
</constant>
<constant name="RETURN_CELL_VALUE" value="0" enum="CellularReturnType">
The cellular distance function will return the same value for all points within a cell.
diff --git a/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml b/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml
index 182fe32f9c..c174ee4d69 100644
--- a/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml
+++ b/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml
@@ -235,7 +235,7 @@
<return type="int" />
<param index="0" name="next_pointer" type="void*" />
<description>
- Adds additional data structures when interogating OpenXR system abilities.
+ Adds additional data structures when querying OpenXR system abilities.
</description>
</method>
<method name="_set_viewport_composition_layer_and_get_next_pointer" qualifiers="virtual">
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index a6fd727290..1775541757 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -2036,8 +2036,9 @@ bool OpenXRAPI::poll_events() {
if (local_floor_emulation.enabled) {
local_floor_emulation.should_reset_floor_height = true;
}
- if (event->poseValid && xr_interface) {
- xr_interface->on_pose_recentered();
+
+ if (xr_interface) {
+ xr_interface->on_reference_space_change_pending();
}
} break;
case XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED: {
diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp
index 8e0c672e58..68e04694e3 100644
--- a/modules/openxr/openxr_interface.cpp
+++ b/modules/openxr/openxr_interface.cpp
@@ -1134,6 +1134,12 @@ void OpenXRInterface::process() {
if (head.is_valid()) {
head->set_pose("default", head_transform, head_linear_velocity, head_angular_velocity, head_confidence);
}
+
+ if (reference_stage_changing) {
+ // Now that we have updated tracking information in our updated reference space, trigger our pose recentered signal.
+ emit_signal(SNAME("pose_recentered"));
+ reference_stage_changing = false;
+ }
}
void OpenXRInterface::pre_render() {
@@ -1315,8 +1321,8 @@ void OpenXRInterface::on_state_exiting() {
emit_signal(SNAME("instance_exiting"));
}
-void OpenXRInterface::on_pose_recentered() {
- emit_signal(SNAME("pose_recentered"));
+void OpenXRInterface::on_reference_space_change_pending() {
+ reference_stage_changing = true;
}
void OpenXRInterface::on_refresh_rate_changes(float p_new_rate) {
diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h
index f0ee0dc3c4..d1bf2aaf78 100644
--- a/modules/openxr/openxr_interface.h
+++ b/modules/openxr/openxr_interface.h
@@ -70,6 +70,7 @@ class OpenXRInterface : public XRInterface {
private:
OpenXRAPI *openxr_api = nullptr;
bool initialized = false;
+ bool reference_stage_changing = false;
XRInterface::TrackingStatus tracking_state;
// At a minimum we need a tracker for our head
@@ -207,7 +208,7 @@ public:
void on_state_stopping();
void on_state_loss_pending();
void on_state_exiting();
- void on_pose_recentered();
+ void on_reference_space_change_pending();
void on_refresh_rate_changes(float p_new_rate);
void tracker_profile_changed(RID p_tracker, RID p_interaction_profile);
diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml
index e12dc43b6f..66e7cd5a0b 100644
--- a/modules/regex/doc_classes/RegEx.xml
+++ b/modules/regex/doc_classes/RegEx.xml
@@ -34,14 +34,14 @@
print(result.get_string("digit"))
# Would print 01 03 0 3f 42
[/codeblock]
- [b]Example of splitting a string using a RegEx:[/b]
+ [b]Example:[/b] Split a string using a RegEx:
[codeblock]
var regex = RegEx.new()
regex.compile("\\S+") # Negated whitespace character class.
var results = []
for result in regex.search_all("One Two \n\tThree"):
results.push_back(result.get_string())
- # The `results` array now contains "One", "Two", "Three".
+ # The `results` array now contains "One", "Two", and "Three".
[/codeblock]
[b]Note:[/b] Godot's regex implementation is based on the [url=https://www.pcre.org/]PCRE2[/url] library. You can view the full pattern reference [url=https://www.pcre.org/current/doc/html/pcre2pattern.html]here[/url].
[b]Tip:[/b] You can use [url=https://regexr.com/]Regexr[/url] to test regular expressions online.
diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp
index b9d493b844..1f7d5504b6 100644
--- a/modules/svg/image_loader_svg.cpp
+++ b/modules/svg/image_loader_svg.cpp
@@ -53,7 +53,7 @@ void ImageLoaderSVG::_replace_color_property(const HashMap<Color, Color> &p_colo
int pos = r_string.find(p_prefix);
while (pos != -1) {
pos += prefix_len; // Skip prefix.
- int end_pos = r_string.find("\"", pos);
+ int end_pos = r_string.find_char('"', pos);
ERR_FAIL_COND_MSG(end_pos == -1, vformat("Malformed SVG string after property \"%s\".", p_prefix));
const String color_code = r_string.substr(pos, end_pos - pos);
if (color_code != "none" && !color_code.begins_with("url(")) {
diff --git a/modules/text_server_adv/thorvg_svg_in_ot.cpp b/modules/text_server_adv/thorvg_svg_in_ot.cpp
index 136ccf3aaf..f546c5bca6 100644
--- a/modules/text_server_adv/thorvg_svg_in_ot.cpp
+++ b/modules/text_server_adv/thorvg_svg_in_ot.cpp
@@ -57,8 +57,6 @@ using namespace godot;
#include "thorvg_svg_in_ot.h"
-#include "thorvg_bounds_iterator.h"
-
#include <freetype/otsvg.h>
#include <ft2build.h>
@@ -92,8 +90,9 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
parser.instantiate();
parser->_open_buffer((const uint8_t *)document->svg_document, document->svg_document_length);
- float aspect = 1.0f;
String xml_body;
+ double embox_x = document->units_per_EM;
+ double embox_y = document->units_per_EM;
while (parser->read() == OK) {
if (parser->has_attribute("id")) {
const String &gl_name = parser->get_named_attribute_value("id");
@@ -111,15 +110,26 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
PackedStringArray vb = parser->get_named_attribute_value("viewBox").split(" ");
if (vb.size() == 4) {
- aspect = vb[2].to_float() / vb[3].to_float();
+ embox_x = vb[2].to_float();
+ embox_y = vb[3].to_float();
}
}
- continue;
+ if (parser->has_attribute("width")) {
+ embox_x = parser->get_named_attribute_value("width").to_float();
+ }
+ if (parser->has_attribute("height")) {
+ embox_y = parser->get_named_attribute_value("height").to_float();
+ }
}
if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
xml_body += vformat("<%s", parser->get_node_name());
+ bool is_svg_tag = parser->get_node_name() == "svg";
for (int i = 0; i < parser->get_attribute_count(); i++) {
- xml_body += vformat(" %s=\"%s\"", parser->get_attribute_name(i), parser->get_attribute_value(i));
+ String aname = parser->get_attribute_name(i);
+ if (is_svg_tag && (aname == "viewBox" || aname == "width" || aname == "height")) {
+ continue;
+ }
+ xml_body += vformat(" %s=\"%s\"", aname, parser->get_attribute_value(i));
}
if (parser->is_empty()) {
@@ -133,91 +143,78 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
xml_body += vformat("</%s>", parser->get_node_name());
}
}
- String temp_xml_str = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 1 1\">" + xml_body;
- CharString temp_xml = temp_xml_str.utf8();
std::unique_ptr<tvg::Picture> picture = tvg::Picture::gen();
- tvg::Result result = picture->load(temp_xml.get_data(), temp_xml.length(), "svg+xml", false);
- if (result != tvg::Result::Success) {
- ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (bounds detection).");
- }
-
- float min_x = INFINITY, min_y = INFINITY, max_x = -INFINITY, max_y = -INFINITY;
- tvg_get_bounds(picture.get(), min_x, min_y, max_x, max_y);
+ gl_state.xml_code = xml_body.utf8();
- float new_h = (max_y - min_y);
- float new_w = (max_x - min_x);
-
- if (new_h * aspect >= new_w) {
- new_w = (new_h * aspect);
- } else {
- new_h = (new_w / aspect);
+ tvg::Result result = picture->load(gl_state.xml_code.get_data(), gl_state.xml_code.length(), "svg+xml", false);
+ if (result != tvg::Result::Success) {
+ ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (glyph metrics).");
}
- String xml_code_str = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"" + rtos(min_x) + " " + rtos(min_y) + " " + rtos(new_w) + " " + rtos(new_h) + "\">" + xml_body;
- gl_state.xml_code = xml_code_str.utf8();
+ float svg_width, svg_height;
+ picture->size(&svg_width, &svg_height);
+ double aspect = svg_width / svg_height;
- picture = tvg::Picture::gen();
- result = picture->load(gl_state.xml_code.get_data(), gl_state.xml_code.length(), "svg+xml", false);
+ result = picture->size(embox_x * aspect, embox_y);
if (result != tvg::Result::Success) {
- ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (glyph metrics).");
+ ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to resize SVG document.");
}
- float x_svg_to_out, y_svg_to_out;
- x_svg_to_out = (float)metrics.x_ppem / new_w;
- y_svg_to_out = (float)metrics.y_ppem / new_h;
+ double x_svg_to_out = (double)metrics.x_ppem / embox_x;
+ double y_svg_to_out = (double)metrics.y_ppem / embox_y;
- gl_state.m.e11 = (double)document->transform.xx / (1 << 16) * x_svg_to_out;
- gl_state.m.e12 = -(double)document->transform.xy / (1 << 16) * x_svg_to_out;
- gl_state.m.e21 = -(double)document->transform.yx / (1 << 16) * y_svg_to_out;
- gl_state.m.e22 = (double)document->transform.yy / (1 << 16) * y_svg_to_out;
- gl_state.m.e13 = (double)document->delta.x / 64 * new_w / metrics.x_ppem;
- gl_state.m.e23 = -(double)document->delta.y / 64 * new_h / metrics.y_ppem;
+ gl_state.m.e11 = (double)document->transform.xx / (1 << 16);
+ gl_state.m.e12 = -(double)document->transform.xy / (1 << 16);
+ gl_state.m.e21 = -(double)document->transform.yx / (1 << 16);
+ gl_state.m.e22 = (double)document->transform.yy / (1 << 16);
+ gl_state.m.e13 = (double)document->delta.x / 64 * embox_x / metrics.x_ppem;
+ gl_state.m.e23 = -(double)document->delta.y / 64 * embox_y / metrics.y_ppem;
gl_state.m.e31 = 0;
gl_state.m.e32 = 0;
gl_state.m.e33 = 1;
- result = picture->transform(gl_state.m);
+ result = picture->size(embox_x * aspect * x_svg_to_out, embox_y * y_svg_to_out);
if (result != tvg::Result::Success) {
- ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to apply transform to SVG document.");
+ ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to resize SVG document.");
}
- result = picture->bounds(&gl_state.x, &gl_state.y, &gl_state.w, &gl_state.h, true);
+ result = picture->transform(gl_state.m);
if (result != tvg::Result::Success) {
- ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to get SVG bounds.");
+ ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to apply transform to SVG document.");
}
- gl_state.bmp_y = gl_state.h + metrics.descender / 64.f;
- gl_state.bmp_x = 0;
+ picture->size(&gl_state.w, &gl_state.h);
+ gl_state.x = (gl_state.h - gl_state.w) / 2.0;
+ gl_state.y = -gl_state.h;
gl_state.ready = true;
}
- p_slot->bitmap_left = (FT_Int)gl_state.bmp_x;
- p_slot->bitmap_top = (FT_Int)gl_state.bmp_y;
+ p_slot->bitmap_left = (FT_Int)gl_state.x;
+ p_slot->bitmap_top = (FT_Int)-gl_state.y;
- float tmp = ceil(gl_state.h);
- p_slot->bitmap.rows = (unsigned int)tmp;
- tmp = ceil(gl_state.w);
- p_slot->bitmap.width = (unsigned int)tmp;
+ double tmpd = Math::ceil(gl_state.h);
+ p_slot->bitmap.rows = (unsigned int)tmpd;
+ tmpd = Math::ceil(gl_state.w);
+ p_slot->bitmap.width = (unsigned int)tmpd;
p_slot->bitmap.pitch = (int)p_slot->bitmap.width * 4;
+
p_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
- float metrics_width, metrics_height;
- float horiBearingX, horiBearingY;
- float vertBearingX, vertBearingY;
+ float metrics_width = (float)gl_state.w;
+ float metrics_height = (float)gl_state.h;
+
+ float horiBearingX = (float)gl_state.x;
+ float horiBearingY = (float)-gl_state.y;
- metrics_width = (float)gl_state.w;
- metrics_height = (float)gl_state.h;
- horiBearingX = (float)gl_state.x;
- horiBearingY = (float)-gl_state.y;
- vertBearingX = p_slot->metrics.horiBearingX / 64.0f - p_slot->metrics.horiAdvance / 64.0f / 2;
- vertBearingY = (p_slot->metrics.vertAdvance / 64.0f - p_slot->metrics.height / 64.0f) / 2;
+ float vertBearingX = p_slot->metrics.horiBearingX / 64.0f - p_slot->metrics.horiAdvance / 64.0f / 2;
+ float vertBearingY = (p_slot->metrics.vertAdvance / 64.0f - p_slot->metrics.height / 64.0f) / 2;
- tmp = roundf(metrics_width * 64);
- p_slot->metrics.width = (FT_Pos)tmp;
- tmp = roundf(metrics_height * 64);
- p_slot->metrics.height = (FT_Pos)tmp;
+ float tmpf = Math::round(metrics_width * 64);
+ p_slot->metrics.width = (FT_Pos)tmpf;
+ tmpf = Math::round(metrics_height * 64);
+ p_slot->metrics.height = (FT_Pos)tmpf;
p_slot->metrics.horiBearingX = (FT_Pos)(horiBearingX * 64);
p_slot->metrics.horiBearingY = (FT_Pos)(horiBearingY * 64);
@@ -250,6 +247,10 @@ FT_Error tvg_svg_in_ot_render(FT_GlyphSlot p_slot, FT_Pointer *p_state) {
if (res != tvg::Result::Success) {
ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (glyph rendering).");
}
+ res = picture->size(gl_state.w, gl_state.h);
+ if (res != tvg::Result::Success) {
+ ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to resize SVG document.");
+ }
res = picture->transform(gl_state.m);
if (res != tvg::Result::Success) {
ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to apply transform to SVG document.");
diff --git a/modules/text_server_adv/thorvg_svg_in_ot.h b/modules/text_server_adv/thorvg_svg_in_ot.h
index ce048674fd..a0e7e3a1d2 100644
--- a/modules/text_server_adv/thorvg_svg_in_ot.h
+++ b/modules/text_server_adv/thorvg_svg_in_ot.h
@@ -60,8 +60,6 @@ using namespace godot;
struct GL_State {
bool ready = false;
- float bmp_x = 0;
- float bmp_y = 0;
float x = 0;
float y = 0;
float w = 0;
diff --git a/modules/text_server_fb/thorvg_svg_in_ot.cpp b/modules/text_server_fb/thorvg_svg_in_ot.cpp
index 1ad33a88d4..f546c5bca6 100644
--- a/modules/text_server_fb/thorvg_svg_in_ot.cpp
+++ b/modules/text_server_fb/thorvg_svg_in_ot.cpp
@@ -49,7 +49,7 @@ using namespace godot;
#include "core/typedefs.h"
#include "core/variant/variant.h"
-#include "modules/modules_enabled.gen.h" // For svg.
+#include "modules/modules_enabled.gen.h" // For svg, freetype.
#endif
#ifdef MODULE_SVG_ENABLED
@@ -57,8 +57,6 @@ using namespace godot;
#include "thorvg_svg_in_ot.h"
-#include "thorvg_bounds_iterator.h"
-
#include <freetype/otsvg.h>
#include <ft2build.h>
@@ -92,8 +90,9 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
parser.instantiate();
parser->_open_buffer((const uint8_t *)document->svg_document, document->svg_document_length);
- float aspect = 1.0f;
String xml_body;
+ double embox_x = document->units_per_EM;
+ double embox_y = document->units_per_EM;
while (parser->read() == OK) {
if (parser->has_attribute("id")) {
const String &gl_name = parser->get_named_attribute_value("id");
@@ -111,15 +110,26 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
PackedStringArray vb = parser->get_named_attribute_value("viewBox").split(" ");
if (vb.size() == 4) {
- aspect = vb[2].to_float() / vb[3].to_float();
+ embox_x = vb[2].to_float();
+ embox_y = vb[3].to_float();
}
}
- continue;
+ if (parser->has_attribute("width")) {
+ embox_x = parser->get_named_attribute_value("width").to_float();
+ }
+ if (parser->has_attribute("height")) {
+ embox_y = parser->get_named_attribute_value("height").to_float();
+ }
}
if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
xml_body += vformat("<%s", parser->get_node_name());
+ bool is_svg_tag = parser->get_node_name() == "svg";
for (int i = 0; i < parser->get_attribute_count(); i++) {
- xml_body += vformat(" %s=\"%s\"", parser->get_attribute_name(i), parser->get_attribute_value(i));
+ String aname = parser->get_attribute_name(i);
+ if (is_svg_tag && (aname == "viewBox" || aname == "width" || aname == "height")) {
+ continue;
+ }
+ xml_body += vformat(" %s=\"%s\"", aname, parser->get_attribute_value(i));
}
if (parser->is_empty()) {
@@ -133,91 +143,78 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
xml_body += vformat("</%s>", parser->get_node_name());
}
}
- String temp_xml_str = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 1 1\">" + xml_body;
- CharString temp_xml = temp_xml_str.utf8();
std::unique_ptr<tvg::Picture> picture = tvg::Picture::gen();
- tvg::Result result = picture->load(temp_xml.get_data(), temp_xml.length(), "svg+xml", false);
- if (result != tvg::Result::Success) {
- ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (bounds detection).");
- }
-
- float min_x = INFINITY, min_y = INFINITY, max_x = -INFINITY, max_y = -INFINITY;
- tvg_get_bounds(picture.get(), min_x, min_y, max_x, max_y);
+ gl_state.xml_code = xml_body.utf8();
- float new_h = (max_y - min_y);
- float new_w = (max_x - min_x);
-
- if (new_h * aspect >= new_w) {
- new_w = (new_h * aspect);
- } else {
- new_h = (new_w / aspect);
+ tvg::Result result = picture->load(gl_state.xml_code.get_data(), gl_state.xml_code.length(), "svg+xml", false);
+ if (result != tvg::Result::Success) {
+ ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (glyph metrics).");
}
- String xml_code_str = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"" + rtos(min_x) + " " + rtos(min_y) + " " + rtos(new_w) + " " + rtos(new_h) + "\">" + xml_body;
- gl_state.xml_code = xml_code_str.utf8();
+ float svg_width, svg_height;
+ picture->size(&svg_width, &svg_height);
+ double aspect = svg_width / svg_height;
- picture = tvg::Picture::gen();
- result = picture->load(gl_state.xml_code.get_data(), gl_state.xml_code.length(), "svg+xml", false);
+ result = picture->size(embox_x * aspect, embox_y);
if (result != tvg::Result::Success) {
- ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (glyph metrics).");
+ ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to resize SVG document.");
}
- float x_svg_to_out, y_svg_to_out;
- x_svg_to_out = (float)metrics.x_ppem / new_w;
- y_svg_to_out = (float)metrics.y_ppem / new_h;
+ double x_svg_to_out = (double)metrics.x_ppem / embox_x;
+ double y_svg_to_out = (double)metrics.y_ppem / embox_y;
- gl_state.m.e11 = (double)document->transform.xx / (1 << 16) * x_svg_to_out;
- gl_state.m.e12 = -(double)document->transform.xy / (1 << 16) * x_svg_to_out;
- gl_state.m.e21 = -(double)document->transform.yx / (1 << 16) * y_svg_to_out;
- gl_state.m.e22 = (double)document->transform.yy / (1 << 16) * y_svg_to_out;
- gl_state.m.e13 = (double)document->delta.x / 64 * new_w / metrics.x_ppem;
- gl_state.m.e23 = -(double)document->delta.y / 64 * new_h / metrics.y_ppem;
+ gl_state.m.e11 = (double)document->transform.xx / (1 << 16);
+ gl_state.m.e12 = -(double)document->transform.xy / (1 << 16);
+ gl_state.m.e21 = -(double)document->transform.yx / (1 << 16);
+ gl_state.m.e22 = (double)document->transform.yy / (1 << 16);
+ gl_state.m.e13 = (double)document->delta.x / 64 * embox_x / metrics.x_ppem;
+ gl_state.m.e23 = -(double)document->delta.y / 64 * embox_y / metrics.y_ppem;
gl_state.m.e31 = 0;
gl_state.m.e32 = 0;
gl_state.m.e33 = 1;
- result = picture->transform(gl_state.m);
+ result = picture->size(embox_x * aspect * x_svg_to_out, embox_y * y_svg_to_out);
if (result != tvg::Result::Success) {
- ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to apply transform to SVG document.");
+ ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to resize SVG document.");
}
- result = picture->bounds(&gl_state.x, &gl_state.y, &gl_state.w, &gl_state.h, true);
+ result = picture->transform(gl_state.m);
if (result != tvg::Result::Success) {
- ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to get SVG bounds.");
+ ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to apply transform to SVG document.");
}
- gl_state.bmp_y = gl_state.h + metrics.descender / 64.f;
- gl_state.bmp_x = 0;
+ picture->size(&gl_state.w, &gl_state.h);
+ gl_state.x = (gl_state.h - gl_state.w) / 2.0;
+ gl_state.y = -gl_state.h;
gl_state.ready = true;
}
- p_slot->bitmap_left = (FT_Int)gl_state.bmp_x;
- p_slot->bitmap_top = (FT_Int)gl_state.bmp_y;
+ p_slot->bitmap_left = (FT_Int)gl_state.x;
+ p_slot->bitmap_top = (FT_Int)-gl_state.y;
- float tmp = ceil(gl_state.h);
- p_slot->bitmap.rows = (unsigned int)tmp;
- tmp = ceil(gl_state.w);
- p_slot->bitmap.width = (unsigned int)tmp;
+ double tmpd = Math::ceil(gl_state.h);
+ p_slot->bitmap.rows = (unsigned int)tmpd;
+ tmpd = Math::ceil(gl_state.w);
+ p_slot->bitmap.width = (unsigned int)tmpd;
p_slot->bitmap.pitch = (int)p_slot->bitmap.width * 4;
+
p_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
- float metrics_width, metrics_height;
- float horiBearingX, horiBearingY;
- float vertBearingX, vertBearingY;
+ float metrics_width = (float)gl_state.w;
+ float metrics_height = (float)gl_state.h;
+
+ float horiBearingX = (float)gl_state.x;
+ float horiBearingY = (float)-gl_state.y;
- metrics_width = (float)gl_state.w;
- metrics_height = (float)gl_state.h;
- horiBearingX = (float)gl_state.x;
- horiBearingY = (float)-gl_state.y;
- vertBearingX = p_slot->metrics.horiBearingX / 64.0f - p_slot->metrics.horiAdvance / 64.0f / 2;
- vertBearingY = (p_slot->metrics.vertAdvance / 64.0f - p_slot->metrics.height / 64.0f) / 2;
+ float vertBearingX = p_slot->metrics.horiBearingX / 64.0f - p_slot->metrics.horiAdvance / 64.0f / 2;
+ float vertBearingY = (p_slot->metrics.vertAdvance / 64.0f - p_slot->metrics.height / 64.0f) / 2;
- tmp = roundf(metrics_width * 64);
- p_slot->metrics.width = (FT_Pos)tmp;
- tmp = roundf(metrics_height * 64);
- p_slot->metrics.height = (FT_Pos)tmp;
+ float tmpf = Math::round(metrics_width * 64);
+ p_slot->metrics.width = (FT_Pos)tmpf;
+ tmpf = Math::round(metrics_height * 64);
+ p_slot->metrics.height = (FT_Pos)tmpf;
p_slot->metrics.horiBearingX = (FT_Pos)(horiBearingX * 64);
p_slot->metrics.horiBearingY = (FT_Pos)(horiBearingY * 64);
@@ -250,6 +247,10 @@ FT_Error tvg_svg_in_ot_render(FT_GlyphSlot p_slot, FT_Pointer *p_state) {
if (res != tvg::Result::Success) {
ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (glyph rendering).");
}
+ res = picture->size(gl_state.w, gl_state.h);
+ if (res != tvg::Result::Success) {
+ ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to resize SVG document.");
+ }
res = picture->transform(gl_state.m);
if (res != tvg::Result::Success) {
ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to apply transform to SVG document.");
diff --git a/modules/text_server_fb/thorvg_svg_in_ot.h b/modules/text_server_fb/thorvg_svg_in_ot.h
index ce048674fd..a0e7e3a1d2 100644
--- a/modules/text_server_fb/thorvg_svg_in_ot.h
+++ b/modules/text_server_fb/thorvg_svg_in_ot.h
@@ -60,8 +60,6 @@ using namespace godot;
struct GL_State {
bool ready = false;
- float bmp_x = 0;
- float bmp_y = 0;
float x = 0;
float y = 0;
float w = 0;
diff --git a/modules/upnp/SCsub b/modules/upnp/SCsub
index 6657d75cae..ba4a842cb6 100644
--- a/modules/upnp/SCsub
+++ b/modules/upnp/SCsub
@@ -10,7 +10,7 @@ env_upnp = env_modules.Clone()
thirdparty_obj = []
-if env["builtin_miniupnpc"]:
+if env["builtin_miniupnpc"] and env["platform"] != "web":
thirdparty_dir = "#thirdparty/miniupnpc/"
thirdparty_sources = [
"igd_desc_parse.c",
diff --git a/modules/upnp/register_types.cpp b/modules/upnp/register_types.cpp
index f6a34837a2..fdf39c0b33 100644
--- a/modules/upnp/register_types.cpp
+++ b/modules/upnp/register_types.cpp
@@ -33,6 +33,11 @@
#include "upnp.h"
#include "upnp_device.h"
+#ifndef WEB_ENABLED
+#include "upnp_device_miniupnp.h"
+#include "upnp_miniupnp.h"
+#endif
+
#include "core/error/error_macros.h"
void initialize_upnp_module(ModuleInitializationLevel p_level) {
@@ -40,8 +45,13 @@ void initialize_upnp_module(ModuleInitializationLevel p_level) {
return;
}
- GDREGISTER_CLASS(UPNP);
- GDREGISTER_CLASS(UPNPDevice);
+ ClassDB::register_custom_instance_class<UPNP>();
+ ClassDB::register_custom_instance_class<UPNPDevice>();
+
+#ifndef WEB_ENABLED
+ UPNPMiniUPNP::make_default();
+ UPNPDeviceMiniUPNP::make_default();
+#endif
}
void uninitialize_upnp_module(ModuleInitializationLevel p_level) {
diff --git a/modules/upnp/upnp.cpp b/modules/upnp/upnp.cpp
index 4305bf842a..5ec0b984fc 100644
--- a/modules/upnp/upnp.cpp
+++ b/modules/upnp/upnp.cpp
@@ -30,298 +30,7 @@
#include "upnp.h"
-#include <miniwget.h>
-#include <upnpcommands.h>
-
-#include <stdlib.h>
-
-bool UPNP::is_common_device(const String &dev) const {
- return dev.is_empty() ||
- dev.contains("InternetGatewayDevice") ||
- dev.contains("WANIPConnection") ||
- dev.contains("WANPPPConnection") ||
- dev.contains("rootdevice");
-}
-
-int UPNP::discover(int timeout, int ttl, const String &device_filter) {
- ERR_FAIL_COND_V_MSG(timeout < 0, UPNP_RESULT_INVALID_PARAM, "The response's wait time can't be negative.");
- ERR_FAIL_COND_V_MSG(ttl < 0 || ttl > 255, UPNP_RESULT_INVALID_PARAM, "The time-to-live must be set between 0 and 255 (inclusive).");
-
- devices.clear();
-
- int error = 0;
- struct UPNPDev *devlist;
-
- CharString cs = discover_multicast_if.utf8();
- const char *m_if = cs.length() ? cs.get_data() : nullptr;
- if (is_common_device(device_filter)) {
- devlist = upnpDiscover(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error);
- } else {
- devlist = upnpDiscoverAll(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error);
- }
-
- if (error != UPNPDISCOVER_SUCCESS) {
- switch (error) {
- case UPNPDISCOVER_SOCKET_ERROR:
- return UPNP_RESULT_SOCKET_ERROR;
- case UPNPDISCOVER_MEMORY_ERROR:
- return UPNP_RESULT_MEM_ALLOC_ERROR;
- default:
- return UPNP_RESULT_UNKNOWN_ERROR;
- }
- }
-
- if (!devlist) {
- return UPNP_RESULT_NO_DEVICES;
- }
-
- struct UPNPDev *dev = devlist;
-
- while (dev) {
- if (device_filter.is_empty() || strstr(dev->st, device_filter.utf8().get_data())) {
- add_device_to_list(dev, devlist);
- }
-
- dev = dev->pNext;
- }
-
- freeUPNPDevlist(devlist);
-
- return UPNP_RESULT_SUCCESS;
-}
-
-void UPNP::add_device_to_list(UPNPDev *dev, UPNPDev *devlist) {
- Ref<UPNPDevice> new_device;
- new_device.instantiate();
-
- new_device->set_description_url(dev->descURL);
- new_device->set_service_type(dev->st);
-
- parse_igd(new_device, devlist);
-
- devices.push_back(new_device);
-}
-
-char *UPNP::load_description(const String &url, int *size, int *status_code) const {
- return (char *)miniwget(url.utf8().get_data(), size, 0, status_code);
-}
-
-void UPNP::parse_igd(Ref<UPNPDevice> dev, UPNPDev *devlist) {
- int size = 0;
- int status_code = -1;
- char *xml = load_description(dev->get_description_url(), &size, &status_code);
-
- if (status_code != 200) {
- dev->set_igd_status(UPNPDevice::IGD_STATUS_HTTP_ERROR);
- return;
- }
-
- if (!xml || size < 1) {
- dev->set_igd_status(UPNPDevice::IGD_STATUS_HTTP_EMPTY);
- return;
- }
-
- struct UPNPUrls urls = {};
- struct IGDdatas data;
-
- parserootdesc(xml, size, &data);
- free(xml);
- xml = nullptr;
-
- GetUPNPUrls(&urls, &data, dev->get_description_url().utf8().get_data(), 0);
-
- char addr[16];
-#if MINIUPNPC_API_VERSION >= 18
- int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16, nullptr, 0);
-#else
- int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16);
-#endif
-
- if (i != 1) {
- FreeUPNPUrls(&urls);
-
- switch (i) {
- case 0:
- dev->set_igd_status(UPNPDevice::IGD_STATUS_NO_IGD);
- return;
- case 2:
- dev->set_igd_status(UPNPDevice::IGD_STATUS_DISCONNECTED);
- return;
- case 3:
- dev->set_igd_status(UPNPDevice::IGD_STATUS_UNKNOWN_DEVICE);
- return;
- default:
- dev->set_igd_status(UPNPDevice::IGD_STATUS_UNKNOWN_ERROR);
- return;
- }
- }
-
- if (urls.controlURL[0] == '\0') {
- FreeUPNPUrls(&urls);
- dev->set_igd_status(UPNPDevice::IGD_STATUS_INVALID_CONTROL);
- return;
- }
-
- dev->set_igd_control_url(urls.controlURL);
- dev->set_igd_service_type(data.first.servicetype);
- dev->set_igd_our_addr(addr);
- dev->set_igd_status(UPNPDevice::IGD_STATUS_OK);
-
- FreeUPNPUrls(&urls);
-}
-
-int UPNP::upnp_result(int in) {
- switch (in) {
- case UPNPCOMMAND_SUCCESS:
- return UPNP_RESULT_SUCCESS;
- case UPNPCOMMAND_UNKNOWN_ERROR:
- return UPNP_RESULT_UNKNOWN_ERROR;
- case UPNPCOMMAND_INVALID_ARGS:
- return UPNP_RESULT_INVALID_ARGS;
- case UPNPCOMMAND_HTTP_ERROR:
- return UPNP_RESULT_HTTP_ERROR;
- case UPNPCOMMAND_INVALID_RESPONSE:
- return UPNP_RESULT_INVALID_RESPONSE;
- case UPNPCOMMAND_MEM_ALLOC_ERROR:
- return UPNP_RESULT_MEM_ALLOC_ERROR;
-
- case 402:
- return UPNP_RESULT_INVALID_ARGS;
- case 403:
- return UPNP_RESULT_NOT_AUTHORIZED;
- case 501:
- return UPNP_RESULT_ACTION_FAILED;
- case 606:
- return UPNP_RESULT_NOT_AUTHORIZED;
- case 714:
- return UPNP_RESULT_NO_SUCH_ENTRY_IN_ARRAY;
- case 715:
- return UPNP_RESULT_SRC_IP_WILDCARD_NOT_PERMITTED;
- case 716:
- return UPNP_RESULT_EXT_PORT_WILDCARD_NOT_PERMITTED;
- case 718:
- return UPNP_RESULT_CONFLICT_WITH_OTHER_MAPPING;
- case 724:
- return UPNP_RESULT_SAME_PORT_VALUES_REQUIRED;
- case 725:
- return UPNP_RESULT_ONLY_PERMANENT_LEASE_SUPPORTED;
- case 726:
- return UPNP_RESULT_REMOTE_HOST_MUST_BE_WILDCARD;
- case 727:
- return UPNP_RESULT_EXT_PORT_MUST_BE_WILDCARD;
- case 728:
- return UPNP_RESULT_NO_PORT_MAPS_AVAILABLE;
- case 729:
- return UPNP_RESULT_CONFLICT_WITH_OTHER_MECHANISM;
- case 732:
- return UPNP_RESULT_INT_PORT_WILDCARD_NOT_PERMITTED;
- case 733:
- return UPNP_RESULT_INCONSISTENT_PARAMETERS;
- }
-
- return UPNP_RESULT_UNKNOWN_ERROR;
-}
-
-int UPNP::get_device_count() const {
- return devices.size();
-}
-
-Ref<UPNPDevice> UPNP::get_device(int index) const {
- ERR_FAIL_INDEX_V(index, devices.size(), nullptr);
-
- return devices.get(index);
-}
-
-void UPNP::add_device(Ref<UPNPDevice> device) {
- ERR_FAIL_COND(device.is_null());
-
- devices.push_back(device);
-}
-
-void UPNP::set_device(int index, Ref<UPNPDevice> device) {
- ERR_FAIL_INDEX(index, devices.size());
- ERR_FAIL_COND(device.is_null());
-
- devices.set(index, device);
-}
-
-void UPNP::remove_device(int index) {
- ERR_FAIL_INDEX(index, devices.size());
-
- devices.remove_at(index);
-}
-
-void UPNP::clear_devices() {
- devices.clear();
-}
-
-Ref<UPNPDevice> UPNP::get_gateway() const {
- ERR_FAIL_COND_V_MSG(devices.is_empty(), nullptr, "Couldn't find any UPNPDevices.");
-
- for (int i = 0; i < devices.size(); i++) {
- Ref<UPNPDevice> dev = get_device(i);
-
- if (dev.is_valid() && dev->is_valid_gateway()) {
- return dev;
- }
- }
-
- return nullptr;
-}
-
-void UPNP::set_discover_multicast_if(const String &m_if) {
- discover_multicast_if = m_if;
-}
-
-String UPNP::get_discover_multicast_if() const {
- return discover_multicast_if;
-}
-
-void UPNP::set_discover_local_port(int port) {
- discover_local_port = port;
-}
-
-int UPNP::get_discover_local_port() const {
- return discover_local_port;
-}
-
-void UPNP::set_discover_ipv6(bool ipv6) {
- discover_ipv6 = ipv6;
-}
-
-bool UPNP::is_discover_ipv6() const {
- return discover_ipv6;
-}
-
-String UPNP::query_external_address() const {
- Ref<UPNPDevice> dev = get_gateway();
-
- if (dev.is_null()) {
- return "";
- }
-
- return dev->query_external_address();
-}
-
-int UPNP::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const {
- Ref<UPNPDevice> dev = get_gateway();
-
- if (dev.is_null()) {
- return UPNP_RESULT_NO_GATEWAY;
- }
-
- return dev->add_port_mapping(port, port_internal, desc, proto, duration);
-}
-
-int UPNP::delete_port_mapping(int port, String proto) const {
- Ref<UPNPDevice> dev = get_gateway();
-
- if (dev.is_null()) {
- return UPNP_RESULT_NO_GATEWAY;
- }
-
- return dev->delete_port_mapping(port, proto);
-}
+UPNP *(*UPNP::_create)(bool p_notify_postinitialize) = nullptr;
void UPNP::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_device_count"), &UPNP::get_device_count);
@@ -382,9 +91,3 @@ void UPNP::_bind_methods() {
BIND_ENUM_CONSTANT(UPNP_RESULT_NO_DEVICES);
BIND_ENUM_CONSTANT(UPNP_RESULT_UNKNOWN_ERROR);
}
-
-UPNP::UPNP() {
-}
-
-UPNP::~UPNP() {
-}
diff --git a/modules/upnp/upnp.h b/modules/upnp/upnp.h
index dc9bbdbc22..566b01ecdc 100644
--- a/modules/upnp/upnp.h
+++ b/modules/upnp/upnp.h
@@ -35,26 +35,14 @@
#include "core/object/ref_counted.h"
-#include <miniupnpc.h>
-
class UPNP : public RefCounted {
GDCLASS(UPNP, RefCounted);
-private:
- String discover_multicast_if = "";
- int discover_local_port = 0;
- bool discover_ipv6 = false;
-
- Vector<Ref<UPNPDevice>> devices;
-
- bool is_common_device(const String &dev) const;
- void add_device_to_list(UPNPDev *dev, UPNPDev *devlist);
- void parse_igd(Ref<UPNPDevice> dev, UPNPDev *devlist);
- char *load_description(const String &url, int *size, int *status_code) const;
-
protected:
static void _bind_methods();
+ static UPNP *(*_create)(bool p_notify_postinitialize);
+
public:
enum UPNPResult {
UPNP_RESULT_SUCCESS,
@@ -88,35 +76,40 @@ public:
UPNP_RESULT_UNKNOWN_ERROR,
};
- static int upnp_result(int in);
+ static UPNP *create(bool p_notify_postinitialize = true) {
+ if (!_create) {
+ return nullptr;
+ }
+ return _create(p_notify_postinitialize);
+ }
- int get_device_count() const;
- Ref<UPNPDevice> get_device(int index) const;
- void add_device(Ref<UPNPDevice> device);
- void set_device(int index, Ref<UPNPDevice> device);
- void remove_device(int index);
- void clear_devices();
+ virtual int get_device_count() const = 0;
+ virtual Ref<UPNPDevice> get_device(int index) const = 0;
+ virtual void add_device(Ref<UPNPDevice> device) = 0;
+ virtual void set_device(int index, Ref<UPNPDevice> device) = 0;
+ virtual void remove_device(int index) = 0;
+ virtual void clear_devices() = 0;
- Ref<UPNPDevice> get_gateway() const;
+ virtual Ref<UPNPDevice> get_gateway() const = 0;
- int discover(int timeout = 2000, int ttl = 2, const String &device_filter = "InternetGatewayDevice");
+ virtual int discover(int timeout = 2000, int ttl = 2, const String &device_filter = "InternetGatewayDevice") = 0;
- String query_external_address() const;
+ virtual String query_external_address() const = 0;
- int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const;
- int delete_port_mapping(int port, String proto = "UDP") const;
+ virtual int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const = 0;
+ virtual int delete_port_mapping(int port, String proto = "UDP") const = 0;
- void set_discover_multicast_if(const String &m_if);
- String get_discover_multicast_if() const;
+ virtual void set_discover_multicast_if(const String &m_if) = 0;
+ virtual String get_discover_multicast_if() const = 0;
- void set_discover_local_port(int port);
- int get_discover_local_port() const;
+ virtual void set_discover_local_port(int port) = 0;
+ virtual int get_discover_local_port() const = 0;
- void set_discover_ipv6(bool ipv6);
- bool is_discover_ipv6() const;
+ virtual void set_discover_ipv6(bool ipv6) = 0;
+ virtual bool is_discover_ipv6() const = 0;
- UPNP();
- ~UPNP();
+ UPNP() {}
+ virtual ~UPNP() {}
};
VARIANT_ENUM_CAST(UPNP::UPNPResult)
diff --git a/modules/upnp/upnp_device.cpp b/modules/upnp/upnp_device.cpp
index 11ee3681af..45766281f1 100644
--- a/modules/upnp/upnp_device.cpp
+++ b/modules/upnp/upnp_device.cpp
@@ -30,119 +30,7 @@
#include "upnp_device.h"
-#include "upnp.h"
-
-#include <upnpcommands.h>
-
-String UPNPDevice::query_external_address() const {
- ERR_FAIL_COND_V_MSG(!is_valid_gateway(), "", "The Internet Gateway Device must be valid.");
-
- char addr[16];
- int i = UPNP_GetExternalIPAddress(
- igd_control_url.utf8().get_data(),
- igd_service_type.utf8().get_data(),
- (char *)&addr);
-
- ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, "", "Couldn't get external IP address.");
-
- return String(addr);
-}
-
-int UPNPDevice::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const {
- ERR_FAIL_COND_V_MSG(!is_valid_gateway(), UPNP::UPNP_RESULT_INVALID_GATEWAY, "The Internet Gateway Device must be valid.");
- ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive).");
- ERR_FAIL_COND_V_MSG(port_internal < 0 || port_internal > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 0 and 65535 (inclusive)."); // Needs to allow 0 because 0 signifies "use external port as internal port"
- ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP.");
- ERR_FAIL_COND_V_MSG(duration < 0, UPNP::UPNP_RESULT_INVALID_DURATION, "The port mapping's lease duration can't be negative.");
-
- if (port_internal < 1) {
- port_internal = port;
- }
-
- int i = UPNP_AddPortMapping(
- igd_control_url.utf8().get_data(),
- igd_service_type.utf8().get_data(),
- itos(port).utf8().get_data(),
- itos(port_internal).utf8().get_data(),
- igd_our_addr.utf8().get_data(),
- desc.is_empty() ? nullptr : desc.utf8().get_data(),
- proto.utf8().get_data(),
- nullptr, // Remote host, always nullptr as IGDs don't support it
- duration > 0 ? itos(duration).utf8().get_data() : nullptr);
-
- ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i), "Couldn't add port mapping.");
-
- return UPNP::UPNP_RESULT_SUCCESS;
-}
-
-int UPNPDevice::delete_port_mapping(int port, String proto) const {
- ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive).");
- ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP.");
-
- int i = UPNP_DeletePortMapping(
- igd_control_url.utf8().get_data(),
- igd_service_type.utf8().get_data(),
- itos(port).utf8().get_data(),
- proto.utf8().get_data(),
- nullptr // Remote host, always nullptr as IGDs don't support it
- );
-
- ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNP::upnp_result(i), "Couldn't delete port mapping.");
-
- return UPNP::UPNP_RESULT_SUCCESS;
-}
-
-void UPNPDevice::set_description_url(const String &url) {
- description_url = url;
-}
-
-String UPNPDevice::get_description_url() const {
- return description_url;
-}
-
-void UPNPDevice::set_service_type(const String &type) {
- service_type = type;
-}
-
-String UPNPDevice::get_service_type() const {
- return service_type;
-}
-
-void UPNPDevice::set_igd_control_url(const String &url) {
- igd_control_url = url;
-}
-
-String UPNPDevice::get_igd_control_url() const {
- return igd_control_url;
-}
-
-void UPNPDevice::set_igd_service_type(const String &type) {
- igd_service_type = type;
-}
-
-String UPNPDevice::get_igd_service_type() const {
- return igd_service_type;
-}
-
-void UPNPDevice::set_igd_our_addr(const String &addr) {
- igd_our_addr = addr;
-}
-
-String UPNPDevice::get_igd_our_addr() const {
- return igd_our_addr;
-}
-
-void UPNPDevice::set_igd_status(IGDStatus status) {
- igd_status = status;
-}
-
-UPNPDevice::IGDStatus UPNPDevice::get_igd_status() const {
- return igd_status;
-}
-
-bool UPNPDevice::is_valid_gateway() const {
- return igd_status == IGD_STATUS_OK;
-}
+UPNPDevice *(*UPNPDevice::_create)(bool p_notify_postinitialize) = nullptr;
void UPNPDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_valid_gateway"), &UPNPDevice::is_valid_gateway);
@@ -185,15 +73,3 @@ void UPNPDevice::_bind_methods() {
BIND_ENUM_CONSTANT(IGD_STATUS_MALLOC_ERROR);
BIND_ENUM_CONSTANT(IGD_STATUS_UNKNOWN_ERROR);
}
-
-UPNPDevice::UPNPDevice() {
- description_url = "";
- service_type = "";
- igd_control_url = "";
- igd_service_type = "";
- igd_our_addr = "";
- igd_status = IGD_STATUS_UNKNOWN_ERROR;
-}
-
-UPNPDevice::~UPNPDevice() {
-}
diff --git a/modules/upnp/upnp_device.h b/modules/upnp/upnp_device.h
index a49e574890..fdc5bab110 100644
--- a/modules/upnp/upnp_device.h
+++ b/modules/upnp/upnp_device.h
@@ -36,6 +36,11 @@
class UPNPDevice : public RefCounted {
GDCLASS(UPNPDevice, RefCounted);
+protected:
+ static void _bind_methods();
+
+ static UPNPDevice *(*_create)(bool p_notify_postinitialize);
+
public:
enum IGDStatus {
IGD_STATUS_OK,
@@ -50,42 +55,38 @@ public:
IGD_STATUS_UNKNOWN_ERROR,
};
- void set_description_url(const String &url);
- String get_description_url() const;
+ static UPNPDevice *create(bool p_notify_postinitialize = true) {
+ if (!_create) {
+ return nullptr;
+ }
+ return _create(p_notify_postinitialize);
+ }
- void set_service_type(const String &type);
- String get_service_type() const;
+ virtual void set_description_url(const String &url) = 0;
+ virtual String get_description_url() const = 0;
- void set_igd_control_url(const String &url);
- String get_igd_control_url() const;
+ virtual void set_service_type(const String &type) = 0;
+ virtual String get_service_type() const = 0;
- void set_igd_service_type(const String &type);
- String get_igd_service_type() const;
+ virtual void set_igd_control_url(const String &url) = 0;
+ virtual String get_igd_control_url() const = 0;
- void set_igd_our_addr(const String &addr);
- String get_igd_our_addr() const;
+ virtual void set_igd_service_type(const String &type) = 0;
+ virtual String get_igd_service_type() const = 0;
- void set_igd_status(IGDStatus status);
- IGDStatus get_igd_status() const;
+ virtual void set_igd_our_addr(const String &addr) = 0;
+ virtual String get_igd_our_addr() const = 0;
- bool is_valid_gateway() const;
- String query_external_address() const;
- int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const;
- int delete_port_mapping(int port, String proto = "UDP") const;
+ virtual void set_igd_status(IGDStatus status) = 0;
+ virtual IGDStatus get_igd_status() const = 0;
- UPNPDevice();
- ~UPNPDevice();
-
-protected:
- static void _bind_methods();
+ virtual bool is_valid_gateway() const = 0;
+ virtual String query_external_address() const = 0;
+ virtual int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const = 0;
+ virtual int delete_port_mapping(int port, String proto = "UDP") const = 0;
-private:
- String description_url;
- String service_type;
- String igd_control_url;
- String igd_service_type;
- String igd_our_addr;
- IGDStatus igd_status;
+ UPNPDevice() {}
+ virtual ~UPNPDevice() {}
};
VARIANT_ENUM_CAST(UPNPDevice::IGDStatus)
diff --git a/modules/upnp/upnp_device_miniupnp.cpp b/modules/upnp/upnp_device_miniupnp.cpp
new file mode 100644
index 0000000000..46319f83d3
--- /dev/null
+++ b/modules/upnp/upnp_device_miniupnp.cpp
@@ -0,0 +1,153 @@
+/**************************************************************************/
+/* upnp_device_miniupnp.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef WEB_ENABLED
+
+#include "upnp_device_miniupnp.h"
+
+#include "upnp_miniupnp.h"
+
+#include <upnpcommands.h>
+
+void UPNPDeviceMiniUPNP::make_default() {
+ UPNPDevice::_create = UPNPDeviceMiniUPNP::_create;
+}
+
+String UPNPDeviceMiniUPNP::query_external_address() const {
+ ERR_FAIL_COND_V_MSG(!is_valid_gateway(), "", "The Internet Gateway Device must be valid.");
+
+ char addr[16];
+ int i = UPNP_GetExternalIPAddress(
+ igd_control_url.utf8().get_data(),
+ igd_service_type.utf8().get_data(),
+ (char *)&addr);
+
+ ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, "", "Couldn't get external IP address.");
+
+ return String(addr);
+}
+
+int UPNPDeviceMiniUPNP::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const {
+ ERR_FAIL_COND_V_MSG(!is_valid_gateway(), UPNP::UPNP_RESULT_INVALID_GATEWAY, "The Internet Gateway Device must be valid.");
+ ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive).");
+ ERR_FAIL_COND_V_MSG(port_internal < 0 || port_internal > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 0 and 65535 (inclusive)."); // Needs to allow 0 because 0 signifies "use external port as internal port"
+ ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP.");
+ ERR_FAIL_COND_V_MSG(duration < 0, UPNP::UPNP_RESULT_INVALID_DURATION, "The port mapping's lease duration can't be negative.");
+
+ if (port_internal < 1) {
+ port_internal = port;
+ }
+
+ int i = UPNP_AddPortMapping(
+ igd_control_url.utf8().get_data(),
+ igd_service_type.utf8().get_data(),
+ itos(port).utf8().get_data(),
+ itos(port_internal).utf8().get_data(),
+ igd_our_addr.utf8().get_data(),
+ desc.is_empty() ? nullptr : desc.utf8().get_data(),
+ proto.utf8().get_data(),
+ nullptr, // Remote host, always nullptr as IGDs don't support it
+ duration > 0 ? itos(duration).utf8().get_data() : nullptr);
+
+ ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNPMiniUPNP::upnp_result(i), "Couldn't add port mapping.");
+
+ return UPNP::UPNP_RESULT_SUCCESS;
+}
+
+int UPNPDeviceMiniUPNP::delete_port_mapping(int port, String proto) const {
+ ERR_FAIL_COND_V_MSG(port < 1 || port > 65535, UPNP::UPNP_RESULT_INVALID_PORT, "The port number must be set between 1 and 65535 (inclusive).");
+ ERR_FAIL_COND_V_MSG(proto != "UDP" && proto != "TCP", UPNP::UPNP_RESULT_INVALID_PROTOCOL, "The protocol must be either TCP or UDP.");
+
+ int i = UPNP_DeletePortMapping(
+ igd_control_url.utf8().get_data(),
+ igd_service_type.utf8().get_data(),
+ itos(port).utf8().get_data(),
+ proto.utf8().get_data(),
+ nullptr // Remote host, always nullptr as IGDs don't support it
+ );
+
+ ERR_FAIL_COND_V_MSG(i != UPNPCOMMAND_SUCCESS, UPNPMiniUPNP::upnp_result(i), "Couldn't delete port mapping.");
+
+ return UPNP::UPNP_RESULT_SUCCESS;
+}
+
+void UPNPDeviceMiniUPNP::set_description_url(const String &url) {
+ description_url = url;
+}
+
+String UPNPDeviceMiniUPNP::get_description_url() const {
+ return description_url;
+}
+
+void UPNPDeviceMiniUPNP::set_service_type(const String &type) {
+ service_type = type;
+}
+
+String UPNPDeviceMiniUPNP::get_service_type() const {
+ return service_type;
+}
+
+void UPNPDeviceMiniUPNP::set_igd_control_url(const String &url) {
+ igd_control_url = url;
+}
+
+String UPNPDeviceMiniUPNP::get_igd_control_url() const {
+ return igd_control_url;
+}
+
+void UPNPDeviceMiniUPNP::set_igd_service_type(const String &type) {
+ igd_service_type = type;
+}
+
+String UPNPDeviceMiniUPNP::get_igd_service_type() const {
+ return igd_service_type;
+}
+
+void UPNPDeviceMiniUPNP::set_igd_our_addr(const String &addr) {
+ igd_our_addr = addr;
+}
+
+String UPNPDeviceMiniUPNP::get_igd_our_addr() const {
+ return igd_our_addr;
+}
+
+void UPNPDeviceMiniUPNP::set_igd_status(IGDStatus status) {
+ igd_status = status;
+}
+
+UPNPDeviceMiniUPNP::IGDStatus UPNPDeviceMiniUPNP::get_igd_status() const {
+ return igd_status;
+}
+
+bool UPNPDeviceMiniUPNP::is_valid_gateway() const {
+ return igd_status == IGD_STATUS_OK;
+}
+
+#endif // WEB_ENABLED
diff --git a/modules/upnp/upnp_device_miniupnp.h b/modules/upnp/upnp_device_miniupnp.h
new file mode 100644
index 0000000000..bea3b1d542
--- /dev/null
+++ b/modules/upnp/upnp_device_miniupnp.h
@@ -0,0 +1,83 @@
+/**************************************************************************/
+/* upnp_device_miniupnp.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef UPNP_DEVICE_MINIUPNP_H
+#define UPNP_DEVICE_MINIUPNP_H
+
+#ifndef WEB_ENABLED
+
+#include "upnp_device.h"
+
+class UPNPDeviceMiniUPNP : public UPNPDevice {
+ GDCLASS(UPNPDeviceMiniUPNP, UPNPDevice);
+
+private:
+ static UPNPDevice *_create(bool p_notify_postinitialize) { return static_cast<UPNPDevice *>(ClassDB::creator<UPNPDeviceMiniUPNP>(p_notify_postinitialize)); }
+
+ String description_url;
+ String service_type;
+ String igd_control_url;
+ String igd_service_type;
+ String igd_our_addr;
+ IGDStatus igd_status = IGD_STATUS_UNKNOWN_ERROR;
+
+public:
+ static void make_default();
+
+ virtual void set_description_url(const String &url) override;
+ virtual String get_description_url() const override;
+
+ virtual void set_service_type(const String &type) override;
+ virtual String get_service_type() const override;
+
+ virtual void set_igd_control_url(const String &url) override;
+ virtual String get_igd_control_url() const override;
+
+ virtual void set_igd_service_type(const String &type) override;
+ virtual String get_igd_service_type() const override;
+
+ virtual void set_igd_our_addr(const String &addr) override;
+ virtual String get_igd_our_addr() const override;
+
+ virtual void set_igd_status(IGDStatus status) override;
+ virtual IGDStatus get_igd_status() const override;
+
+ virtual bool is_valid_gateway() const override;
+ virtual String query_external_address() const override;
+ virtual int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const override;
+ virtual int delete_port_mapping(int port, String proto = "UDP") const override;
+
+ UPNPDeviceMiniUPNP() {}
+ virtual ~UPNPDeviceMiniUPNP() {}
+};
+
+#endif // WEB_ENABLED
+
+#endif // UPNP_DEVICE_MINIUPNP_H
diff --git a/modules/upnp/upnp_miniupnp.cpp b/modules/upnp/upnp_miniupnp.cpp
new file mode 100644
index 0000000000..0714d56a08
--- /dev/null
+++ b/modules/upnp/upnp_miniupnp.cpp
@@ -0,0 +1,334 @@
+/**************************************************************************/
+/* upnp_miniupnp.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef WEB_ENABLED
+
+#include "upnp_miniupnp.h"
+
+#include "upnp_device_miniupnp.h"
+
+#include <miniwget.h>
+#include <upnpcommands.h>
+
+#include <stdlib.h>
+
+void UPNPMiniUPNP::make_default() {
+ UPNP::_create = UPNPMiniUPNP::_create;
+}
+
+bool UPNPMiniUPNP::is_common_device(const String &dev) const {
+ return dev.is_empty() ||
+ dev.contains("InternetGatewayDevice") ||
+ dev.contains("WANIPConnection") ||
+ dev.contains("WANPPPConnection") ||
+ dev.contains("rootdevice");
+}
+
+int UPNPMiniUPNP::discover(int timeout, int ttl, const String &device_filter) {
+ ERR_FAIL_COND_V_MSG(timeout < 0, UPNP_RESULT_INVALID_PARAM, "The response's wait time can't be negative.");
+ ERR_FAIL_COND_V_MSG(ttl < 0 || ttl > 255, UPNP_RESULT_INVALID_PARAM, "The time-to-live must be set between 0 and 255 (inclusive).");
+
+ devices.clear();
+
+ int error = 0;
+ struct UPNPDev *devlist;
+
+ CharString cs = discover_multicast_if.utf8();
+ const char *m_if = cs.length() ? cs.get_data() : nullptr;
+ if (is_common_device(device_filter)) {
+ devlist = upnpDiscover(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error);
+ } else {
+ devlist = upnpDiscoverAll(timeout, m_if, nullptr, discover_local_port, discover_ipv6, ttl, &error);
+ }
+
+ if (error != UPNPDISCOVER_SUCCESS) {
+ switch (error) {
+ case UPNPDISCOVER_SOCKET_ERROR:
+ return UPNP_RESULT_SOCKET_ERROR;
+ case UPNPDISCOVER_MEMORY_ERROR:
+ return UPNP_RESULT_MEM_ALLOC_ERROR;
+ default:
+ return UPNP_RESULT_UNKNOWN_ERROR;
+ }
+ }
+
+ if (!devlist) {
+ return UPNP_RESULT_NO_DEVICES;
+ }
+
+ struct UPNPDev *dev = devlist;
+
+ while (dev) {
+ if (device_filter.is_empty() || strstr(dev->st, device_filter.utf8().get_data())) {
+ add_device_to_list(dev, devlist);
+ }
+
+ dev = dev->pNext;
+ }
+
+ freeUPNPDevlist(devlist);
+
+ return UPNP_RESULT_SUCCESS;
+}
+
+void UPNPMiniUPNP::add_device_to_list(UPNPDev *dev, UPNPDev *devlist) {
+ Ref<UPNPDeviceMiniUPNP> new_device;
+ new_device.instantiate();
+
+ new_device->set_description_url(dev->descURL);
+ new_device->set_service_type(dev->st);
+
+ parse_igd(new_device, devlist);
+
+ devices.push_back(new_device);
+}
+
+char *UPNPMiniUPNP::load_description(const String &url, int *size, int *status_code) const {
+ return (char *)miniwget(url.utf8().get_data(), size, 0, status_code);
+}
+
+void UPNPMiniUPNP::parse_igd(Ref<UPNPDevice> dev, UPNPDev *devlist) {
+ int size = 0;
+ int status_code = -1;
+ char *xml = load_description(dev->get_description_url(), &size, &status_code);
+
+ if (status_code != 200) {
+ dev->set_igd_status(UPNPDevice::IGD_STATUS_HTTP_ERROR);
+ return;
+ }
+
+ if (!xml || size < 1) {
+ dev->set_igd_status(UPNPDevice::IGD_STATUS_HTTP_EMPTY);
+ return;
+ }
+
+ struct UPNPUrls urls = {};
+ struct IGDdatas data;
+
+ parserootdesc(xml, size, &data);
+ free(xml);
+ xml = nullptr;
+
+ GetUPNPUrls(&urls, &data, dev->get_description_url().utf8().get_data(), 0);
+
+ char addr[16];
+#if MINIUPNPC_API_VERSION >= 18
+ int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16, nullptr, 0);
+#else
+ int i = UPNP_GetValidIGD(devlist, &urls, &data, (char *)&addr, 16);
+#endif
+
+ if (i != 1) {
+ FreeUPNPUrls(&urls);
+
+ switch (i) {
+ case 0:
+ dev->set_igd_status(UPNPDevice::IGD_STATUS_NO_IGD);
+ return;
+ case 2:
+ dev->set_igd_status(UPNPDevice::IGD_STATUS_DISCONNECTED);
+ return;
+ case 3:
+ dev->set_igd_status(UPNPDevice::IGD_STATUS_UNKNOWN_DEVICE);
+ return;
+ default:
+ dev->set_igd_status(UPNPDevice::IGD_STATUS_UNKNOWN_ERROR);
+ return;
+ }
+ }
+
+ if (urls.controlURL[0] == '\0') {
+ FreeUPNPUrls(&urls);
+ dev->set_igd_status(UPNPDevice::IGD_STATUS_INVALID_CONTROL);
+ return;
+ }
+
+ dev->set_igd_control_url(urls.controlURL);
+ dev->set_igd_service_type(data.first.servicetype);
+ dev->set_igd_our_addr(addr);
+ dev->set_igd_status(UPNPDevice::IGD_STATUS_OK);
+
+ FreeUPNPUrls(&urls);
+}
+
+int UPNPMiniUPNP::upnp_result(int in) {
+ switch (in) {
+ case UPNPCOMMAND_SUCCESS:
+ return UPNP_RESULT_SUCCESS;
+ case UPNPCOMMAND_UNKNOWN_ERROR:
+ return UPNP_RESULT_UNKNOWN_ERROR;
+ case UPNPCOMMAND_INVALID_ARGS:
+ return UPNP_RESULT_INVALID_ARGS;
+ case UPNPCOMMAND_HTTP_ERROR:
+ return UPNP_RESULT_HTTP_ERROR;
+ case UPNPCOMMAND_INVALID_RESPONSE:
+ return UPNP_RESULT_INVALID_RESPONSE;
+ case UPNPCOMMAND_MEM_ALLOC_ERROR:
+ return UPNP_RESULT_MEM_ALLOC_ERROR;
+
+ case 402:
+ return UPNP_RESULT_INVALID_ARGS;
+ case 403:
+ return UPNP_RESULT_NOT_AUTHORIZED;
+ case 501:
+ return UPNP_RESULT_ACTION_FAILED;
+ case 606:
+ return UPNP_RESULT_NOT_AUTHORIZED;
+ case 714:
+ return UPNP_RESULT_NO_SUCH_ENTRY_IN_ARRAY;
+ case 715:
+ return UPNP_RESULT_SRC_IP_WILDCARD_NOT_PERMITTED;
+ case 716:
+ return UPNP_RESULT_EXT_PORT_WILDCARD_NOT_PERMITTED;
+ case 718:
+ return UPNP_RESULT_CONFLICT_WITH_OTHER_MAPPING;
+ case 724:
+ return UPNP_RESULT_SAME_PORT_VALUES_REQUIRED;
+ case 725:
+ return UPNP_RESULT_ONLY_PERMANENT_LEASE_SUPPORTED;
+ case 726:
+ return UPNP_RESULT_REMOTE_HOST_MUST_BE_WILDCARD;
+ case 727:
+ return UPNP_RESULT_EXT_PORT_MUST_BE_WILDCARD;
+ case 728:
+ return UPNP_RESULT_NO_PORT_MAPS_AVAILABLE;
+ case 729:
+ return UPNP_RESULT_CONFLICT_WITH_OTHER_MECHANISM;
+ case 732:
+ return UPNP_RESULT_INT_PORT_WILDCARD_NOT_PERMITTED;
+ case 733:
+ return UPNP_RESULT_INCONSISTENT_PARAMETERS;
+ }
+
+ return UPNP_RESULT_UNKNOWN_ERROR;
+}
+
+int UPNPMiniUPNP::get_device_count() const {
+ return devices.size();
+}
+
+Ref<UPNPDevice> UPNPMiniUPNP::get_device(int index) const {
+ ERR_FAIL_INDEX_V(index, devices.size(), nullptr);
+
+ return devices.get(index);
+}
+
+void UPNPMiniUPNP::add_device(Ref<UPNPDevice> device) {
+ ERR_FAIL_COND(device.is_null());
+
+ devices.push_back(device);
+}
+
+void UPNPMiniUPNP::set_device(int index, Ref<UPNPDevice> device) {
+ ERR_FAIL_INDEX(index, devices.size());
+ ERR_FAIL_COND(device.is_null());
+
+ devices.set(index, device);
+}
+
+void UPNPMiniUPNP::remove_device(int index) {
+ ERR_FAIL_INDEX(index, devices.size());
+
+ devices.remove_at(index);
+}
+
+void UPNPMiniUPNP::clear_devices() {
+ devices.clear();
+}
+
+Ref<UPNPDevice> UPNPMiniUPNP::get_gateway() const {
+ ERR_FAIL_COND_V_MSG(devices.is_empty(), nullptr, "Couldn't find any UPNPDevices.");
+
+ for (int i = 0; i < devices.size(); i++) {
+ Ref<UPNPDevice> dev = get_device(i);
+
+ if (dev.is_valid() && dev->is_valid_gateway()) {
+ return dev;
+ }
+ }
+
+ return nullptr;
+}
+
+void UPNPMiniUPNP::set_discover_multicast_if(const String &m_if) {
+ discover_multicast_if = m_if;
+}
+
+String UPNPMiniUPNP::get_discover_multicast_if() const {
+ return discover_multicast_if;
+}
+
+void UPNPMiniUPNP::set_discover_local_port(int port) {
+ discover_local_port = port;
+}
+
+int UPNPMiniUPNP::get_discover_local_port() const {
+ return discover_local_port;
+}
+
+void UPNPMiniUPNP::set_discover_ipv6(bool ipv6) {
+ discover_ipv6 = ipv6;
+}
+
+bool UPNPMiniUPNP::is_discover_ipv6() const {
+ return discover_ipv6;
+}
+
+String UPNPMiniUPNP::query_external_address() const {
+ Ref<UPNPDevice> dev = get_gateway();
+
+ if (dev.is_null()) {
+ return "";
+ }
+
+ return dev->query_external_address();
+}
+
+int UPNPMiniUPNP::add_port_mapping(int port, int port_internal, String desc, String proto, int duration) const {
+ Ref<UPNPDevice> dev = get_gateway();
+
+ if (dev.is_null()) {
+ return UPNP_RESULT_NO_GATEWAY;
+ }
+
+ return dev->add_port_mapping(port, port_internal, desc, proto, duration);
+}
+
+int UPNPMiniUPNP::delete_port_mapping(int port, String proto) const {
+ Ref<UPNPDevice> dev = get_gateway();
+
+ if (dev.is_null()) {
+ return UPNP_RESULT_NO_GATEWAY;
+ }
+
+ return dev->delete_port_mapping(port, proto);
+}
+
+#endif // WEB_ENABLED
diff --git a/modules/upnp/upnp_miniupnp.h b/modules/upnp/upnp_miniupnp.h
new file mode 100644
index 0000000000..0c7dba9d0b
--- /dev/null
+++ b/modules/upnp/upnp_miniupnp.h
@@ -0,0 +1,93 @@
+/**************************************************************************/
+/* upnp_miniupnp.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef UPNP_MINIUPNP_H
+#define UPNP_MINIUPNP_H
+
+#ifndef WEB_ENABLED
+
+#include "upnp.h"
+
+#include <miniupnpc.h>
+
+class UPNPMiniUPNP : public UPNP {
+ GDCLASS(UPNPMiniUPNP, UPNP);
+
+private:
+ static UPNP *_create(bool p_notify_postinitialize) { return static_cast<UPNP *>(ClassDB::creator<UPNPMiniUPNP>(p_notify_postinitialize)); }
+
+ String discover_multicast_if = "";
+ int discover_local_port = 0;
+ bool discover_ipv6 = false;
+
+ Vector<Ref<UPNPDevice>> devices;
+
+ bool is_common_device(const String &dev) const;
+ void add_device_to_list(UPNPDev *dev, UPNPDev *devlist);
+ void parse_igd(Ref<UPNPDevice> dev, UPNPDev *devlist);
+ char *load_description(const String &url, int *size, int *status_code) const;
+
+public:
+ static void make_default();
+
+ static int upnp_result(int in);
+
+ virtual int get_device_count() const override;
+ virtual Ref<UPNPDevice> get_device(int index) const override;
+ virtual void add_device(Ref<UPNPDevice> device) override;
+ virtual void set_device(int index, Ref<UPNPDevice> device) override;
+ virtual void remove_device(int index) override;
+ virtual void clear_devices() override;
+
+ virtual Ref<UPNPDevice> get_gateway() const override;
+
+ virtual int discover(int timeout = 2000, int ttl = 2, const String &device_filter = "InternetGatewayDevice") override;
+
+ virtual String query_external_address() const override;
+
+ virtual int add_port_mapping(int port, int port_internal = 0, String desc = "", String proto = "UDP", int duration = 0) const override;
+ virtual int delete_port_mapping(int port, String proto = "UDP") const override;
+
+ virtual void set_discover_multicast_if(const String &m_if) override;
+ virtual String get_discover_multicast_if() const override;
+
+ virtual void set_discover_local_port(int port) override;
+ virtual int get_discover_local_port() const override;
+
+ virtual void set_discover_ipv6(bool ipv6) override;
+ virtual bool is_discover_ipv6() const override;
+
+ UPNPMiniUPNP() {}
+ virtual ~UPNPMiniUPNP() {}
+};
+
+#endif // WEB_ENABLED
+
+#endif // UPNP_MINIUPNP_H
diff --git a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
index 0978e1fcee..b2e1cb345b 100644
--- a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
+++ b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
@@ -60,7 +60,7 @@
<member name="inbound_buffer_size" type="int" setter="set_inbound_buffer_size" getter="get_inbound_buffer_size" default="65535">
The inbound buffer size for connected peers. See [member WebSocketPeer.inbound_buffer_size] for more details.
</member>
- <member name="max_queued_packets" type="int" setter="set_max_queued_packets" getter="get_max_queued_packets" default="2048">
+ <member name="max_queued_packets" type="int" setter="set_max_queued_packets" getter="get_max_queued_packets" default="4096">
The maximum number of queued packets for connected peers. See [member WebSocketPeer.max_queued_packets] for more details.
</member>
<member name="outbound_buffer_size" type="int" setter="set_outbound_buffer_size" getter="get_outbound_buffer_size" default="65535">
diff --git a/modules/websocket/doc_classes/WebSocketPeer.xml b/modules/websocket/doc_classes/WebSocketPeer.xml
index 238dd30536..d329e21b88 100644
--- a/modules/websocket/doc_classes/WebSocketPeer.xml
+++ b/modules/websocket/doc_classes/WebSocketPeer.xml
@@ -155,10 +155,14 @@
The extra HTTP headers to be sent during the WebSocket handshake.
[b]Note:[/b] Not supported in Web exports due to browsers' restrictions.
</member>
+ <member name="heartbeat_interval" type="float" setter="set_heartbeat_interval" getter="get_heartbeat_interval" default="0.0">
+ The interval (in seconds) at which the peer will automatically send WebSocket "ping" control frames. When set to [code]0[/code], no "ping" control frames will be sent.
+ [b]Note:[/b] Has no effect in Web exports due to browser restrictions.
+ </member>
<member name="inbound_buffer_size" type="int" setter="set_inbound_buffer_size" getter="get_inbound_buffer_size" default="65535">
The size of the input buffer in bytes (roughly the maximum amount of memory that will be allocated for the inbound packets).
</member>
- <member name="max_queued_packets" type="int" setter="set_max_queued_packets" getter="get_max_queued_packets" default="2048">
+ <member name="max_queued_packets" type="int" setter="set_max_queued_packets" getter="get_max_queued_packets" default="4096">
The maximum amount of packets that will be allowed in the queues (both inbound and outbound).
</member>
<member name="outbound_buffer_size" type="int" setter="set_outbound_buffer_size" getter="get_outbound_buffer_size" default="65535">
diff --git a/modules/websocket/packet_buffer.h b/modules/websocket/packet_buffer.h
index f98ee12ef9..4ab0579912 100644
--- a/modules/websocket/packet_buffer.h
+++ b/modules/websocket/packet_buffer.h
@@ -104,6 +104,14 @@ public:
return _queued;
}
+ int payload_space_left() const {
+ return _payload.space_left();
+ }
+
+ int packets_space_left() const {
+ return _packets.size() - _queued;
+ }
+
void clear() {
_payload.resize(0);
_packets.resize(0);
diff --git a/modules/websocket/websocket_peer.cpp b/modules/websocket/websocket_peer.cpp
index 95a1a238e9..5c24b5d082 100644
--- a/modules/websocket/websocket_peer.cpp
+++ b/modules/websocket/websocket_peer.cpp
@@ -70,6 +70,9 @@ void WebSocketPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_max_queued_packets", "buffer_size"), &WebSocketPeer::set_max_queued_packets);
ClassDB::bind_method(D_METHOD("get_max_queued_packets"), &WebSocketPeer::get_max_queued_packets);
+ ClassDB::bind_method(D_METHOD("set_heartbeat_interval", "interval"), &WebSocketPeer::set_heartbeat_interval);
+ ClassDB::bind_method(D_METHOD("get_heartbeat_interval"), &WebSocketPeer::get_heartbeat_interval);
+
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "supported_protocols"), "set_supported_protocols", "get_supported_protocols");
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "handshake_headers"), "set_handshake_headers", "get_handshake_headers");
@@ -78,6 +81,8 @@ void WebSocketPeer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_queued_packets"), "set_max_queued_packets", "get_max_queued_packets");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "heartbeat_interval"), "set_heartbeat_interval", "get_heartbeat_interval");
+
BIND_ENUM_CONSTANT(WRITE_MODE_TEXT);
BIND_ENUM_CONSTANT(WRITE_MODE_BINARY);
@@ -151,3 +156,12 @@ void WebSocketPeer::set_max_queued_packets(int p_max_queued_packets) {
int WebSocketPeer::get_max_queued_packets() const {
return max_queued_packets;
}
+
+double WebSocketPeer::get_heartbeat_interval() const {
+ return heartbeat_interval_msec / 1000.0;
+}
+
+void WebSocketPeer::set_heartbeat_interval(double p_interval) {
+ ERR_FAIL_COND(p_interval < 0);
+ heartbeat_interval_msec = p_interval * 1000.0;
+}
diff --git a/modules/websocket/websocket_peer.h b/modules/websocket/websocket_peer.h
index ef0197cf6c..4854122471 100644
--- a/modules/websocket/websocket_peer.h
+++ b/modules/websocket/websocket_peer.h
@@ -71,7 +71,8 @@ protected:
int outbound_buffer_size = DEFAULT_BUFFER_SIZE;
int inbound_buffer_size = DEFAULT_BUFFER_SIZE;
- int max_queued_packets = 2048;
+ int max_queued_packets = 4096;
+ uint64_t heartbeat_interval_msec = 0;
public:
static WebSocketPeer *create(bool p_notify_postinitialize = true) {
@@ -117,6 +118,9 @@ public:
void set_max_queued_packets(int p_max_queued_packets);
int get_max_queued_packets() const;
+ double get_heartbeat_interval() const;
+ void set_heartbeat_interval(double p_interval);
+
WebSocketPeer();
~WebSocketPeer();
};
diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp
index 0c0a046805..81e5673583 100644
--- a/modules/websocket/wsl_peer.cpp
+++ b/modules/websocket/wsl_peer.cpp
@@ -295,6 +295,7 @@ Error WSLPeer::_do_server_handshake() {
resolver.stop();
// Response sent, initialize wslay context.
wslay_event_context_server_init(&wsl_ctx, &_wsl_callbacks, this);
+ wslay_event_config_set_no_buffering(wsl_ctx, 1);
wslay_event_config_set_max_recv_msg_length(wsl_ctx, inbound_buffer_size);
in_buffer.resize(nearest_shift(inbound_buffer_size), max_queued_packets);
packet_buffer.resize(inbound_buffer_size);
@@ -403,6 +404,7 @@ void WSLPeer::_do_client_handshake() {
ERR_FAIL_MSG("Invalid response headers.");
}
wslay_event_context_client_init(&wsl_ctx, &_wsl_callbacks, this);
+ wslay_event_config_set_no_buffering(wsl_ctx, 1);
wslay_event_config_set_max_recv_msg_length(wsl_ctx, inbound_buffer_size);
in_buffer.resize(nearest_shift(inbound_buffer_size), max_queued_packets);
packet_buffer.resize(inbound_buffer_size);
@@ -568,8 +570,15 @@ ssize_t WSLPeer::_wsl_recv_callback(wslay_event_context_ptr ctx, uint8_t *data,
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
return -1;
}
+ // Make sure we don't read more than what our buffer can hold.
+ size_t buffer_limit = MIN(peer->in_buffer.payload_space_left(), peer->in_buffer.packets_space_left() * 2); // The minimum size of a websocket message is 2 bytes.
+ size_t to_read = MIN(len, buffer_limit);
+ if (to_read == 0) {
+ wslay_event_set_error(ctx, WSLAY_ERR_WOULDBLOCK);
+ return -1;
+ }
int read = 0;
- Error err = conn->get_partial_data(data, len, read);
+ Error err = conn->get_partial_data(data, to_read, read);
if (err != OK) {
print_verbose("Websocket get data error: " + itos(err) + ", read (should be 0!): " + itos(read));
wslay_event_set_error(ctx, WSLAY_ERR_CALLBACK_FAILURE);
@@ -582,6 +591,37 @@ ssize_t WSLPeer::_wsl_recv_callback(wslay_event_context_ptr ctx, uint8_t *data,
return read;
}
+void WSLPeer::_wsl_recv_start_callback(wslay_event_context_ptr ctx, const struct wslay_event_on_frame_recv_start_arg *arg, void *user_data) {
+ WSLPeer *peer = (WSLPeer *)user_data;
+ uint8_t op = arg->opcode;
+ if (op == WSLAY_TEXT_FRAME || op == WSLAY_BINARY_FRAME) {
+ // Get ready to process a data package.
+ PendingMessage &pm = peer->pending_message;
+ pm.opcode = op;
+ pm.payload_size = arg->payload_length;
+ }
+}
+
+void WSLPeer::_wsl_frame_recv_chunk_callback(wslay_event_context_ptr ctx, const struct wslay_event_on_frame_recv_chunk_arg *arg, void *user_data) {
+ WSLPeer *peer = (WSLPeer *)user_data;
+ PendingMessage &pm = peer->pending_message;
+ if (pm.opcode != 0) {
+ // Only write the payload.
+ peer->in_buffer.write_packet(arg->data, arg->data_length, nullptr);
+ }
+}
+
+void WSLPeer::_wsl_frame_recv_end_callback(wslay_event_context_ptr ctx, void *user_data) {
+ WSLPeer *peer = (WSLPeer *)user_data;
+ PendingMessage &pm = peer->pending_message;
+ if (pm.opcode != 0) {
+ // Only write the packet (since it's now completed).
+ uint8_t is_string = pm.opcode == WSLAY_TEXT_FRAME ? 1 : 0;
+ peer->in_buffer.write_packet(nullptr, pm.payload_size, &is_string);
+ pm.clear();
+ }
+}
+
ssize_t WSLPeer::_wsl_send_callback(wslay_event_context_ptr ctx, const uint8_t *data, size_t len, int flags, void *user_data) {
WSLPeer *peer = (WSLPeer *)user_data;
Ref<StreamPeer> conn = peer->connection;
@@ -627,25 +667,19 @@ void WSLPeer::_wsl_msg_recv_callback(wslay_event_context_ptr ctx, const struct w
return;
}
- if (peer->ready_state == STATE_CLOSING) {
- return;
- }
-
- if (op == WSLAY_TEXT_FRAME || op == WSLAY_BINARY_FRAME) {
- // Message.
- uint8_t is_string = arg->opcode == WSLAY_TEXT_FRAME ? 1 : 0;
- peer->in_buffer.write_packet(arg->msg, arg->msg_length, &is_string);
+ if (op == WSLAY_PONG) {
+ peer->heartbeat_waiting = false;
}
- // Ping or pong.
+ // Ping, or message (already parsed in chunks).
}
wslay_event_callbacks WSLPeer::_wsl_callbacks = {
_wsl_recv_callback,
_wsl_send_callback,
_wsl_genmask_callback,
- nullptr, /* on_frame_recv_start_callback */
- nullptr, /* on_frame_recv_callback */
- nullptr, /* on_frame_recv_end_callback */
+ _wsl_recv_start_callback,
+ _wsl_frame_recv_chunk_callback,
+ _wsl_frame_recv_end_callback,
_wsl_msg_recv_callback
};
@@ -680,7 +714,31 @@ void WSLPeer::poll() {
if (ready_state == STATE_OPEN || ready_state == STATE_CLOSING) {
ERR_FAIL_NULL(wsl_ctx);
+ uint64_t ticks = OS::get_singleton()->get_ticks_msec();
int err = 0;
+ if (heartbeat_interval_msec != 0 && ticks - last_heartbeat > heartbeat_interval_msec && ready_state == STATE_OPEN) {
+ if (heartbeat_waiting) {
+ wslay_event_context_free(wsl_ctx);
+ wsl_ctx = nullptr;
+ close(-1);
+ return;
+ }
+ heartbeat_waiting = true;
+ struct wslay_event_msg msg;
+ msg.opcode = WSLAY_PING;
+ msg.msg = nullptr;
+ msg.msg_length = 0;
+ err = wslay_event_queue_msg(wsl_ctx, &msg);
+ if (err == 0) {
+ last_heartbeat = ticks;
+ } else {
+ print_verbose("Websocket (wslay) failed to send ping: " + itos(err));
+ wslay_event_context_free(wsl_ctx);
+ wsl_ctx = nullptr;
+ close(-1);
+ return;
+ }
+ }
if ((err = wslay_event_recv(wsl_ctx)) != 0 || (err = wslay_event_send(wsl_ctx)) != 0) {
// Error close.
print_verbose("Websocket (wslay) poll error: " + itos(err));
@@ -689,12 +747,37 @@ void WSLPeer::poll() {
close(-1);
return;
}
- if (wslay_event_get_close_sent(wsl_ctx) && wslay_event_get_close_received(wsl_ctx)) {
- // Clean close.
- wslay_event_context_free(wsl_ctx);
- wsl_ctx = nullptr;
- close(-1);
- return;
+ if (wslay_event_get_close_sent(wsl_ctx)) {
+ if (wslay_event_get_close_received(wsl_ctx)) {
+ // Clean close.
+ wslay_event_context_free(wsl_ctx);
+ wsl_ctx = nullptr;
+ close(-1);
+ return;
+ } else if (!wslay_event_get_read_enabled(wsl_ctx)) {
+ // Some protocol error caused wslay to stop processing incoming events, we'll never receive a close from the other peer.
+ close_code = wslay_event_get_status_code_sent(wsl_ctx);
+ switch (close_code) {
+ case WSLAY_CODE_MESSAGE_TOO_BIG:
+ close_reason = "Message too big";
+ break;
+ case WSLAY_CODE_PROTOCOL_ERROR:
+ close_reason = "Protocol error";
+ break;
+ case WSLAY_CODE_ABNORMAL_CLOSURE:
+ close_reason = "Abnormal closure";
+ break;
+ case WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA:
+ close_reason = "Invalid frame payload data";
+ break;
+ default:
+ close_reason = "Unknown";
+ }
+ wslay_event_context_free(wsl_ctx);
+ wsl_ctx = nullptr;
+ close(-1);
+ return;
+ }
}
}
}
@@ -781,8 +864,10 @@ void WSLPeer::close(int p_code, String p_reason) {
}
}
+ heartbeat_waiting = false;
in_buffer.clear();
packet_buffer.resize(0);
+ pending_message.clear();
}
IPAddress WSLPeer::get_connected_host() const {
diff --git a/modules/websocket/wsl_peer.h b/modules/websocket/wsl_peer.h
index c4fe18630c..45cca48224 100644
--- a/modules/websocket/wsl_peer.h
+++ b/modules/websocket/wsl_peer.h
@@ -53,6 +53,10 @@ private:
// Callbacks.
static ssize_t _wsl_recv_callback(wslay_event_context_ptr ctx, uint8_t *data, size_t len, int flags, void *user_data);
+ static void _wsl_recv_start_callback(wslay_event_context_ptr ctx, const struct wslay_event_on_frame_recv_start_arg *arg, void *user_data);
+ static void _wsl_frame_recv_chunk_callback(wslay_event_context_ptr ctx, const struct wslay_event_on_frame_recv_chunk_arg *arg, void *user_data);
+ static void _wsl_frame_recv_end_callback(wslay_event_context_ptr ctx, void *user_data);
+
static ssize_t _wsl_send_callback(wslay_event_context_ptr ctx, const uint8_t *data, size_t len, int flags, void *user_data);
static int _wsl_genmask_callback(wslay_event_context_ptr ctx, uint8_t *buf, size_t len, void *user_data);
static void _wsl_msg_recv_callback(wslay_event_context_ptr ctx, const struct wslay_event_on_msg_recv_arg *arg, void *user_data);
@@ -80,6 +84,16 @@ private:
Resolver() {}
};
+ struct PendingMessage {
+ size_t payload_size = 0;
+ uint8_t opcode = 0;
+
+ void clear() {
+ payload_size = 0;
+ opcode = 0;
+ }
+ };
+
Resolver resolver;
// WebSocket connection state.
@@ -99,6 +113,9 @@ private:
int close_code = -1;
String close_reason;
uint8_t was_string = 0;
+ uint64_t last_heartbeat = 0;
+ bool heartbeat_waiting = false;
+ PendingMessage pending_message;
// WebSocket configuration.
bool use_tls = true;
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 4bc7e9474b..03a208391c 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -31,6 +31,7 @@ def get_opts():
),
BoolVariable("store_release", "Editor build for Google Play Store (for official builds only)", False),
BoolVariable("generate_apk", "Generate an APK/AAB after building Android library by calling Gradle", False),
+ BoolVariable("swappy", "Use Swappy Frame Pacing library", False),
]
@@ -100,7 +101,7 @@ def detect_swappy():
archs = ["arm64-v8a", "armeabi-v7a", "x86", "x86_64"]
has_swappy = True
for arch in archs:
- if not os.path.isfile("thirdparty/swappy-frame-pacing/" + arch + "/libswappy_static.a"):
+ if not os.path.isfile(f"thirdparty/swappy-frame-pacing/{arch}/libswappy_static.a"):
has_swappy = False
return has_swappy
@@ -176,7 +177,7 @@ def configure(env: "SConsEnvironment"):
env["AS"] = compiler_path + "/clang"
env.Append(
- CCFLAGS=("-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden".split())
+ CCFLAGS=(["-fpic", "-ffunction-sections", "-funwind-tables", "-fstack-protector-strong", "-fvisibility=hidden"])
)
has_swappy = detect_swappy()
@@ -200,28 +201,28 @@ def configure(env: "SConsEnvironment"):
# The NDK adds this if targeting API < 24, so we can drop it when Godot targets it at least
env.Append(CCFLAGS=["-mstackrealign"])
if has_swappy:
- env.Append(LIBPATH=["../../thirdparty/swappy-frame-pacing/x86"])
+ env.Append(LIBPATH=["#thirdparty/swappy-frame-pacing/x86"])
elif env["arch"] == "x86_64":
if has_swappy:
- env.Append(LIBPATH=["../../thirdparty/swappy-frame-pacing/x86_64"])
+ env.Append(LIBPATH=["#thirdparty/swappy-frame-pacing/x86_64"])
elif env["arch"] == "arm32":
- env.Append(CCFLAGS="-march=armv7-a -mfloat-abi=softfp".split())
+ env.Append(CCFLAGS=["-march=armv7-a", "-mfloat-abi=softfp"])
env.Append(CPPDEFINES=["__ARM_ARCH_7__", "__ARM_ARCH_7A__"])
env.Append(CPPDEFINES=["__ARM_NEON__"])
if has_swappy:
- env.Append(LIBPATH=["../../thirdparty/swappy-frame-pacing/armeabi-v7a"])
+ env.Append(LIBPATH=["#thirdparty/swappy-frame-pacing/armeabi-v7a"])
elif env["arch"] == "arm64":
env.Append(CCFLAGS=["-mfix-cortex-a53-835769"])
env.Append(CPPDEFINES=["__ARM_ARCH_8A__"])
if has_swappy:
- env.Append(LIBPATH=["../../thirdparty/swappy-frame-pacing/arm64-v8a"])
+ env.Append(LIBPATH=["#thirdparty/swappy-frame-pacing/arm64-v8a"])
env.Append(CCFLAGS=["-ffp-contract=off"])
# Link flags
- env.Append(LINKFLAGS="-Wl,--gc-sections -Wl,--no-undefined -Wl,-z,now".split())
- env.Append(LINKFLAGS="-Wl,-soname,libgodot_android.so")
+ env.Append(LINKFLAGS=["-Wl,--gc-sections", "-Wl,--no-undefined", "-Wl,-z,now"])
+ env.Append(LINKFLAGS=["-Wl,-soname,libgodot_android.so"])
env.Prepend(CPPPATH=["#platform/android"])
env.Append(CPPDEFINES=["ANDROID_ENABLED", "UNIX_ENABLED"])
diff --git a/platform/android/doc_classes/EditorExportPlatformAndroid.xml b/platform/android/doc_classes/EditorExportPlatformAndroid.xml
index 8c8bca2b7c..983683fd78 100644
--- a/platform/android/doc_classes/EditorExportPlatformAndroid.xml
+++ b/platform/android/doc_classes/EditorExportPlatformAndroid.xml
@@ -151,6 +151,9 @@
<member name="permissions/access_location_extra_commands" type="bool" setter="" getter="">
Allows access to the extra location provider commands. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCESS_LOCATION_EXTRA_COMMANDS]ACCESS_LOCATION_EXTRA_COMMANDS[/url].
</member>
+ <member name="permissions/access_media_location" type="bool" setter="" getter="">
+ Allows an application to access any geographic locations persisted in the user's shared collection. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCESS_MEDIA_LOCATION]ACCESS_MEDIA_LOCATION[/url].
+ </member>
<member name="permissions/access_mock_location" type="bool" setter="" getter="">
Allows an application to create mock location providers for testing.
</member>
@@ -412,6 +415,18 @@
<member name="permissions/read_logs" type="bool" setter="" getter="">
Allows an application to read the low-level system log files. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_LOGS]READ_LOGS[/url].
</member>
+ <member name="permissions/read_media_audio" type="bool" setter="" getter="">
+ Allows an application to read audio files from external storage. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_MEDIA_AUDIO]READ_MEDIA_AUDIO[/url].
+ </member>
+ <member name="permissions/read_media_images" type="bool" setter="" getter="">
+ Allows an application to read image files from external storage. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_MEDIA_IMAGES]READ_MEDIA_IMAGES[/url].
+ </member>
+ <member name="permissions/read_media_video" type="bool" setter="" getter="">
+ Allows an application to read video files from external storage. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_MEDIA_VIDEO]READ_MEDIA_VIDEO[/url].
+ </member>
+ <member name="permissions/read_media_visual_user_selected" type="bool" setter="" getter="">
+ Allows an application to read image or video files from external storage that a user has selected via the permission prompt photo picker. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_MEDIA_VISUAL_USER_SELECTED]READ_MEDIA_VISUAL_USER_SELECTED[/url].
+ </member>
<member name="permissions/read_phone_state" type="bool" setter="" getter="">
Allows read only access to phone state. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_PHONE_STATE]READ_PHONE_STATE[/url].
</member>
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index d2b64c74a4..dc7a287a91 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -37,6 +37,8 @@
#include "editor/editor_settings.h"
#include "editor/export/editor_export.h"
+String get_default_android_sdk_path();
+
void register_android_exporter_types() {
GDREGISTER_VIRTUAL_CLASS(EditorExportPlatformAndroid);
}
@@ -54,8 +56,10 @@ void register_android_exporter() {
#else
EDITOR_DEF_BASIC("export/android/java_sdk_path", OS::get_singleton()->get_environment("JAVA_HOME"));
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/java_sdk_path", PROPERTY_HINT_GLOBAL_DIR));
- EDITOR_DEF_BASIC("export/android/android_sdk_path", OS::get_singleton()->get_environment("ANDROID_HOME"));
+
+ EDITOR_DEF_BASIC("export/android/android_sdk_path", OS::get_singleton()->has_environment("ANDROID_HOME") ? OS::get_singleton()->get_environment("ANDROID_HOME") : get_default_android_sdk_path());
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/android/android_sdk_path", PROPERTY_HINT_GLOBAL_DIR));
+
EDITOR_DEF("export/android/force_system_user", false);
EDITOR_DEF("export/android/shutdown_adb_on_exit", true);
@@ -69,3 +73,15 @@ void register_android_exporter() {
Ref<EditorExportPlatformAndroid> exporter = Ref<EditorExportPlatformAndroid>(memnew(EditorExportPlatformAndroid));
EditorExport::get_singleton()->add_export_platform(exporter);
}
+
+inline String get_default_android_sdk_path() {
+#ifdef WINDOWS_ENABLED
+ return OS::get_singleton()->get_environment("LOCALAPPDATA").path_join("Android/Sdk");
+#elif LINUXBSD_ENABLED
+ return OS::get_singleton()->get_environment("HOME").path_join("Android/Sdk");
+#elif MACOS_ENABLED
+ return OS::get_singleton()->get_environment("HOME").path_join("Library/Android/sdk");
+#else
+ return String();
+#endif
+}
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index ad7ce37819..a7b0879056 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -68,6 +68,7 @@ static const char *android_perms[] = {
"ACCESS_COARSE_LOCATION",
"ACCESS_FINE_LOCATION",
"ACCESS_LOCATION_EXTRA_COMMANDS",
+ "ACCESS_MEDIA_LOCATION",
"ACCESS_MOCK_LOCATION",
"ACCESS_NETWORK_STATE",
"ACCESS_SURFACE_FLINGER",
@@ -155,6 +156,10 @@ static const char *android_perms[] = {
"READ_HISTORY_BOOKMARKS",
"READ_INPUT_STATE",
"READ_LOGS",
+ "READ_MEDIA_AUDIO",
+ "READ_MEDIA_IMAGES",
+ "READ_MEDIA_VIDEO",
+ "READ_MEDIA_VISUAL_USER_SELECTED",
"READ_PHONE_STATE",
"READ_PROFILE",
"READ_SMS",
@@ -783,15 +788,16 @@ Error EditorExportPlatformAndroid::save_apk_so(void *p_userdata, const SharedObj
return OK;
}
-Error EditorExportPlatformAndroid::save_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
+Error EditorExportPlatformAndroid::save_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed) {
APKExportData *ed = static_cast<APKExportData *>(p_userdata);
- String dst_path = p_path.replace_first("res://", "assets/");
+ const String path = ResourceUID::ensure_path(p_path);
+ const String dst_path = path.replace_first("res://", "assets/");
- store_in_apk(ed, dst_path, p_data, _should_compress_asset(p_path, p_data) ? Z_DEFLATED : 0);
+ store_in_apk(ed, dst_path, p_data, _should_compress_asset(path, p_data) ? Z_DEFLATED : 0);
return OK;
}
-Error EditorExportPlatformAndroid::ignore_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
+Error EditorExportPlatformAndroid::ignore_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed) {
return OK;
}
@@ -1559,7 +1565,7 @@ void EditorExportPlatformAndroid::_fix_resources(const Ref<EditorExportPreset> &
str = get_project_name(package_name);
} else {
- String lang = str.substr(str.rfind("-") + 1, str.length()).replace("-", "_");
+ String lang = str.substr(str.rfind_char('-') + 1, str.length()).replace("-", "_");
if (appnames.has(lang)) {
str = appnames[lang];
} else {
@@ -1898,7 +1904,7 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "ext.domain.name"), "com.example.$genname", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name [default if blank]"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/signed"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "package/app_category", PROPERTY_HINT_ENUM, "Accessibility,Audio,Game,Image,Maps,News,Productivity,Social,Video"), APP_CATEGORY_GAME));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "package/app_category", PROPERTY_HINT_ENUM, "Accessibility,Audio,Game,Image,Maps,News,Productivity,Social,Video,Undefined"), APP_CATEGORY_GAME));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/retain_data_on_uninstall"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/exclude_from_recents"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/show_in_android_tv"), false));
@@ -2523,7 +2529,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
// Check for the bin directory.
Ref<DirAccess> da = DirAccess::open(java_sdk_path.path_join("bin"), &errn);
if (errn != OK) {
- err += TTR("Invalid Java SDK path in Editor Settings.");
+ err += TTR("Invalid Java SDK path in Editor Settings.") + " ";
err += TTR("Missing 'bin' directory!");
err += "\n";
valid = false;
@@ -2531,7 +2537,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
// Check for the `java` command.
String java_path = get_java_path();
if (!FileAccess::exists(java_path)) {
- err += TTR("Unable to find 'java' command using the Java SDK path.");
+ err += TTR("Unable to find 'java' command using the Java SDK path.") + " ";
err += TTR("Please check the Java SDK directory specified in Editor Settings.");
err += "\n";
valid = false;
@@ -2548,7 +2554,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
// Check for the platform-tools directory.
Ref<DirAccess> da = DirAccess::open(sdk_path.path_join("platform-tools"), &errn);
if (errn != OK) {
- err += TTR("Invalid Android SDK path in Editor Settings.");
+ err += TTR("Invalid Android SDK path in Editor Settings.") + " ";
err += TTR("Missing 'platform-tools' directory!");
err += "\n";
valid = false;
@@ -2557,7 +2563,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
// Validate that adb is available.
String adb_path = get_adb_path();
if (!FileAccess::exists(adb_path)) {
- err += TTR("Unable to find Android SDK platform-tools' adb command.");
+ err += TTR("Unable to find Android SDK platform-tools' adb command.") + " ";
err += TTR("Please check in the Android SDK directory specified in Editor Settings.");
err += "\n";
valid = false;
@@ -2566,7 +2572,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
// Check for the build-tools directory.
Ref<DirAccess> build_tools_da = DirAccess::open(sdk_path.path_join("build-tools"), &errn);
if (errn != OK) {
- err += TTR("Invalid Android SDK path in Editor Settings.");
+ err += TTR("Invalid Android SDK path in Editor Settings.") + " ";
err += TTR("Missing 'build-tools' directory!");
err += "\n";
valid = false;
@@ -2579,7 +2585,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
// Validate that apksigner is available.
String apksigner_path = get_apksigner_path(target_sdk_version.to_int());
if (!FileAccess::exists(apksigner_path)) {
- err += TTR("Unable to find Android SDK build-tools' apksigner command.");
+ err += TTR("Unable to find Android SDK build-tools' apksigner command.") + " ";
err += TTR("Please check in the Android SDK directory specified in Editor Settings.");
err += "\n";
valid = false;
diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h
index 15e80f824d..23b6f9b193 100644
--- a/platform/android/export/export_plugin.h
+++ b/platform/android/export/export_plugin.h
@@ -142,9 +142,9 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
static Error save_apk_so(void *p_userdata, const SharedObject &p_so);
- static Error save_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
+ static Error save_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed);
- static Error ignore_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
+ static Error ignore_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed);
static Error copy_gradle_so(void *p_userdata, const SharedObject &p_so);
@@ -186,7 +186,7 @@ protected:
void _notification(int p_what);
public:
- typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
+ typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed);
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp
index 9eddef6a4c..433888581f 100644
--- a/platform/android/export/gradle_export_util.cpp
+++ b/platform/android/export/gradle_export_util.cpp
@@ -88,6 +88,8 @@ int _get_app_category_value(int category_index) {
return 7;
case APP_CATEGORY_SOCIAL:
return 4;
+ case APP_CATEGORY_UNDEFINED:
+ return -1;
case APP_CATEGORY_VIDEO:
return 2;
case APP_CATEGORY_GAME:
@@ -167,10 +169,11 @@ Error store_string_at_path(const String &p_path, const String &p_data) {
// It is used by the export_project_files method to save all the asset files into the gradle project.
// It's functionality mirrors that of the method save_apk_file.
// This method will be called ONLY when gradle build is enabled.
-Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
+Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed) {
CustomExportData *export_data = static_cast<CustomExportData *>(p_userdata);
- String dst_path = p_path.replace_first("res://", export_data->assets_directory + "/");
- print_verbose("Saving project files from " + p_path + " into " + dst_path);
+ const String path = ResourceUID::ensure_path(p_path);
+ const String dst_path = path.replace_first("res://", export_data->assets_directory + "/");
+ print_verbose("Saving project files from " + path + " into " + dst_path);
Error err = store_file_at_path(dst_path, p_data);
return err;
}
@@ -311,17 +314,21 @@ String _get_application_tag(const Ref<EditorExportPlatform> &p_export_platform,
" <application android:label=\"@string/godot_project_name_string\"\n"
" android:allowBackup=\"%s\"\n"
" android:icon=\"@mipmap/icon\"\n"
- " android:appCategory=\"%s\"\n"
" android:isGame=\"%s\"\n"
" android:hasFragileUserData=\"%s\"\n"
- " android:requestLegacyExternalStorage=\"%s\"\n"
- " tools:replace=\"android:allowBackup,android:appCategory,android:isGame,android:hasFragileUserData,android:requestLegacyExternalStorage\"\n"
- " tools:ignore=\"GoogleAppIndexingWarning\">\n\n",
+ " android:requestLegacyExternalStorage=\"%s\"\n",
bool_to_string(p_preset->get("user_data_backup/allow")),
- _get_app_category_label(app_category_index),
bool_to_string(is_game),
bool_to_string(p_preset->get("package/retain_data_on_uninstall")),
bool_to_string(p_has_read_write_storage_permission));
+ if (app_category_index != APP_CATEGORY_UNDEFINED) {
+ manifest_application_text += vformat(" android:appCategory=\"%s\"\n", _get_app_category_label(app_category_index));
+ manifest_application_text += " tools:replace=\"android:allowBackup,android:appCategory,android:isGame,android:hasFragileUserData,android:requestLegacyExternalStorage\"\n";
+ } else {
+ manifest_application_text += " tools:remove=\"android:appCategory\"\n";
+ manifest_application_text += " tools:replace=\"android:allowBackup,android:isGame,android:hasFragileUserData,android:requestLegacyExternalStorage\"\n";
+ }
+ manifest_application_text += " tools:ignore=\"GoogleAppIndexingWarning\">\n\n";
Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
for (int i = 0; i < export_plugins.size(); i++) {
diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h
index 9f8e476f73..a528fd5211 100644
--- a/platform/android/export/gradle_export_util.h
+++ b/platform/android/export/gradle_export_util.h
@@ -55,6 +55,7 @@ static const int APP_CATEGORY_NEWS = 5;
static const int APP_CATEGORY_PRODUCTIVITY = 6;
static const int APP_CATEGORY_SOCIAL = 7;
static const int APP_CATEGORY_VIDEO = 8;
+static const int APP_CATEGORY_UNDEFINED = 9;
// Supported XR modes.
// This should match the entries in 'platform/android/java/lib/src/org/godotengine/godot/xr/XRMode.java'
@@ -92,7 +93,7 @@ Error store_string_at_path(const String &p_path, const String &p_data);
// It is used by the export_project_files method to save all the asset files into the gradle project.
// It's functionality mirrors that of the method save_apk_file.
// This method will be called ONLY when gradle build is enabled.
-Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
+Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed);
// Creates strings.xml files inside the gradle project for different locales.
Error _create_project_name_strings_files(const Ref<EditorExportPreset> &p_preset, const String &project_name, const String &p_gradle_build_dir);
diff --git a/platform/android/java/app/res/values/themes.xml b/platform/android/java/app/res/values/themes.xml
index 3ab8401928..3c86e54df5 100644
--- a/platform/android/java/app/res/values/themes.xml
+++ b/platform/android/java/app/res/values/themes.xml
@@ -1,7 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <style name="GodotAppMainTheme" parent="@android:style/Theme.Black.NoTitleBar"/>
+ <style name="GodotAppMainTheme" parent="@android:style/Theme.DeviceDefault.NoActionBar">
+ <item name ="android:windowDrawsSystemBarBackgrounds">false</item>
+ </style>
<style name="GodotAppSplashTheme" parent="Theme.SplashScreen">
<!-- Set the splash screen background, animated icon, and animation
diff --git a/platform/android/java/editor/build.gradle b/platform/android/java/editor/build.gradle
index 45222ca3b0..276d74b75b 100644
--- a/platform/android/java/editor/build.gradle
+++ b/platform/android/java/editor/build.gradle
@@ -173,7 +173,7 @@ dependencies {
implementation "androidx.window:window:1.3.0"
implementation "androidx.core:core-splashscreen:$versions.splashscreenVersion"
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
- implementation "org.bouncycastle:bcprov-jdk15to18:1.77"
+ implementation "org.bouncycastle:bcprov-jdk15to18:1.78"
// Meta dependencies
horizonosImplementation "org.godotengine:godot-openxr-vendors-meta:3.0.0-stable"
diff --git a/platform/android/java/editor/src/main/res/values/themes.xml b/platform/android/java/editor/src/main/res/values/themes.xml
index 2b352247db..8de2c6e288 100644
--- a/platform/android/java/editor/src/main/res/values/themes.xml
+++ b/platform/android/java/editor/src/main/res/values/themes.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <style name="GodotEditorTheme" parent="@android:style/Theme.Black.NoTitleBar.Fullscreen">
+ <style name="GodotEditorTheme" parent="@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen">
+ <item name ="android:windowDrawsSystemBarBackgrounds">false</item>
</style>
<style name="GodotEditorSplashScreenTheme" parent="Theme.SplashScreen.IconBackground">
diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle
index f6aee434e5..f273105efc 100644
--- a/platform/android/java/lib/build.gradle
+++ b/platform/android/java/lib/build.gradle
@@ -106,8 +106,8 @@ android {
boolean devBuild = buildType == "dev"
boolean debugSymbols = devBuild
boolean runTests = devBuild
- boolean productionBuild = !devBuild
boolean storeRelease = buildType == "release"
+ boolean productionBuild = storeRelease
def sconsTarget = flavorName
if (sconsTarget == "template") {
diff --git a/platform/android/net_socket_android.cpp b/platform/android/net_socket_android.cpp
index 8f0ee51fac..9ab7d6a04f 100644
--- a/platform/android/net_socket_android.cpp
+++ b/platform/android/net_socket_android.cpp
@@ -84,7 +84,7 @@ NetSocketAndroid::~NetSocketAndroid() {
}
void NetSocketAndroid::close() {
- NetSocketPosix::close();
+ NetSocketUnix::close();
if (wants_broadcast) {
multicast_lock_release();
}
@@ -96,7 +96,7 @@ void NetSocketAndroid::close() {
}
Error NetSocketAndroid::set_broadcasting_enabled(bool p_enabled) {
- Error err = NetSocketPosix::set_broadcasting_enabled(p_enabled);
+ Error err = NetSocketUnix::set_broadcasting_enabled(p_enabled);
if (err != OK) {
return err;
}
@@ -115,7 +115,7 @@ Error NetSocketAndroid::set_broadcasting_enabled(bool p_enabled) {
}
Error NetSocketAndroid::join_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
- Error err = NetSocketPosix::join_multicast_group(p_multi_address, p_if_name);
+ Error err = NetSocketUnix::join_multicast_group(p_multi_address, p_if_name);
if (err != OK) {
return err;
}
@@ -129,7 +129,7 @@ Error NetSocketAndroid::join_multicast_group(const IPAddress &p_multi_address, c
}
Error NetSocketAndroid::leave_multicast_group(const IPAddress &p_multi_address, const String &p_if_name) {
- Error err = NetSocketPosix::leave_multicast_group(p_multi_address, p_if_name);
+ Error err = NetSocketUnix::leave_multicast_group(p_multi_address, p_if_name);
if (err != OK) {
return err;
}
diff --git a/platform/android/net_socket_android.h b/platform/android/net_socket_android.h
index 26cb2d4e3d..c33146d2d8 100644
--- a/platform/android/net_socket_android.h
+++ b/platform/android/net_socket_android.h
@@ -31,7 +31,7 @@
#ifndef NET_SOCKET_ANDROID_H
#define NET_SOCKET_ANDROID_H
-#include "drivers/unix/net_socket_posix.h"
+#include "drivers/unix/net_socket_unix.h"
#include <jni.h>
@@ -44,7 +44,7 @@
* the lock when broadcasting is enabled/disabled on a socket, or that socket
* joins/leaves a multicast group.
*/
-class NetSocketAndroid : public NetSocketPosix {
+class NetSocketAndroid : public NetSocketUnix {
private:
static jobject net_utils;
static jclass cls;
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 2fd573da75..c8202b147d 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -279,16 +279,18 @@ def configure(env: "SConsEnvironment"):
env.ParseConfig("pkg-config libwebp --cflags --libs")
if not env["builtin_mbedtls"]:
- # mbedTLS does not provide a pkgconfig config yet. See https://github.com/ARMmbed/mbedtls/issues/228
- env.Append(LIBS=["mbedtls", "mbedcrypto", "mbedx509"])
+ # mbedTLS only provides a pkgconfig file since 3.6.0, but we still support 2.28.x,
+ # so fallback to manually specifying LIBS if it fails.
+ if os.system("pkg-config --exists mbedtls") == 0: # 0 means found
+ env.ParseConfig("pkg-config mbedtls mbedcrypto mbedx509 --cflags --libs")
+ else:
+ env.Append(LIBS=["mbedtls", "mbedcrypto", "mbedx509"])
if not env["builtin_wslay"]:
env.ParseConfig("pkg-config libwslay --cflags --libs")
if not env["builtin_miniupnpc"]:
- # No pkgconfig file so far, hardcode default paths.
- env.Prepend(CPPPATH=["/usr/include/miniupnpc"])
- env.Append(LIBS=["miniupnpc"])
+ env.ParseConfig("pkg-config miniupnpc --cflags --libs")
# On Linux wchar_t should be 32-bits
# 16-bit library shouldn't be required due to compiler optimizations
diff --git a/platform/linuxbsd/freedesktop_portal_desktop.cpp b/platform/linuxbsd/freedesktop_portal_desktop.cpp
index 94a748e414..63eed41cd3 100644
--- a/platform/linuxbsd/freedesktop_portal_desktop.cpp
+++ b/platform/linuxbsd/freedesktop_portal_desktop.cpp
@@ -394,7 +394,7 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo
} else {
if (flt == "*.*") {
filter_exts.push_back("*");
- filter_names.push_back(RTR("All Files"));
+ filter_names.push_back(RTR("All Files") + " (*)");
} else {
filter_exts.push_back(flt);
filter_names.push_back(flt);
@@ -405,7 +405,7 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo
}
if (filter_names.is_empty()) {
filter_exts.push_back("*");
- filter_names.push_back(RTR("All Files"));
+ filter_names.push_back(RTR("All Files") + " (*)");
}
DBusError err;
diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp
index e066e78e5b..d8d58ba54b 100644
--- a/platform/linuxbsd/wayland/wayland_thread.cpp
+++ b/platform/linuxbsd/wayland/wayland_thread.cpp
@@ -3988,10 +3988,10 @@ void WaylandThread::selection_set_text(const String &p_text) {
wl_data_source_add_listener(ss->wl_data_source_selection, &wl_data_source_listener, ss);
wl_data_source_offer(ss->wl_data_source_selection, "text/plain;charset=utf-8");
wl_data_source_offer(ss->wl_data_source_selection, "text/plain");
- }
- // TODO: Implement a good way of getting the latest serial from the user.
- wl_data_device_set_selection(ss->wl_data_device, ss->wl_data_source_selection, MAX(ss->pointer_data.button_serial, ss->last_key_pressed_serial));
+ // TODO: Implement a good way of getting the latest serial from the user.
+ wl_data_device_set_selection(ss->wl_data_device, ss->wl_data_source_selection, MAX(ss->pointer_data.button_serial, ss->last_key_pressed_serial));
+ }
// Wait for the message to get to the server before continuing, otherwise the
// clipboard update might come with a delay.
diff --git a/platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.c b/platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.c
index bba21b9cb7..7e1f3b8072 100644
--- a/platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.c
+++ b/platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.c
@@ -1,12 +1,8 @@
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
-// generated by generate-wrapper.py 0.3 on 2023-01-23 15:09:53
-// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/Xcursor/Xcursor.h --sys-include "thirdparty/linuxbsd_headers/X11/Xcursor/Xcursor.h" --soname libXcursor.so.1 --init-name xcursor --output-header ./platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.c
+// generated by generate-wrapper.py 0.6 on 2024-11-09 02:52:36
+// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/Xcursor/Xcursor.h --sys-include thirdparty/linuxbsd_headers/X11/Xcursor/Xcursor.h --soname libXcursor.so.1 --init-name xcursor --output-header ./platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.c --ignore-other
//
-// NOTE: Generated from Xcursor 1.2.0.
-// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existent symbols inherited from
-// libX11, but absent in libXcursor.so.1, were removed.
#include <stdint.h>
#define XcursorImageCreate XcursorImageCreate_dylibloader_orig_xcursor
@@ -130,65 +126,65 @@
#undef XcursorSetThemeCore
#include <dlfcn.h>
#include <stdio.h>
-XcursorImage* (*XcursorImageCreate_dylibloader_wrapper_xcursor)( int, int);
-void (*XcursorImageDestroy_dylibloader_wrapper_xcursor)( XcursorImage*);
-XcursorImages* (*XcursorImagesCreate_dylibloader_wrapper_xcursor)( int);
-void (*XcursorImagesDestroy_dylibloader_wrapper_xcursor)( XcursorImages*);
-void (*XcursorImagesSetName_dylibloader_wrapper_xcursor)( XcursorImages*,const char*);
-XcursorCursors* (*XcursorCursorsCreate_dylibloader_wrapper_xcursor)( Display*, int);
-void (*XcursorCursorsDestroy_dylibloader_wrapper_xcursor)( XcursorCursors*);
-XcursorAnimate* (*XcursorAnimateCreate_dylibloader_wrapper_xcursor)( XcursorCursors*);
-void (*XcursorAnimateDestroy_dylibloader_wrapper_xcursor)( XcursorAnimate*);
-Cursor (*XcursorAnimateNext_dylibloader_wrapper_xcursor)( XcursorAnimate*);
-XcursorComment* (*XcursorCommentCreate_dylibloader_wrapper_xcursor)( XcursorUInt, int);
-void (*XcursorCommentDestroy_dylibloader_wrapper_xcursor)( XcursorComment*);
-XcursorComments* (*XcursorCommentsCreate_dylibloader_wrapper_xcursor)( int);
-void (*XcursorCommentsDestroy_dylibloader_wrapper_xcursor)( XcursorComments*);
-XcursorImage* (*XcursorXcFileLoadImage_dylibloader_wrapper_xcursor)( XcursorFile*, int);
-XcursorImages* (*XcursorXcFileLoadImages_dylibloader_wrapper_xcursor)( XcursorFile*, int);
-XcursorImages* (*XcursorXcFileLoadAllImages_dylibloader_wrapper_xcursor)( XcursorFile*);
-XcursorBool (*XcursorXcFileLoad_dylibloader_wrapper_xcursor)( XcursorFile*, XcursorComments**, XcursorImages**);
-XcursorBool (*XcursorXcFileSave_dylibloader_wrapper_xcursor)( XcursorFile*,const XcursorComments*,const XcursorImages*);
-XcursorImage* (*XcursorFileLoadImage_dylibloader_wrapper_xcursor)( FILE*, int);
-XcursorImages* (*XcursorFileLoadImages_dylibloader_wrapper_xcursor)( FILE*, int);
-XcursorImages* (*XcursorFileLoadAllImages_dylibloader_wrapper_xcursor)( FILE*);
-XcursorBool (*XcursorFileLoad_dylibloader_wrapper_xcursor)( FILE*, XcursorComments**, XcursorImages**);
-XcursorBool (*XcursorFileSaveImages_dylibloader_wrapper_xcursor)( FILE*,const XcursorImages*);
-XcursorBool (*XcursorFileSave_dylibloader_wrapper_xcursor)( FILE*,const XcursorComments*,const XcursorImages*);
-XcursorImage* (*XcursorFilenameLoadImage_dylibloader_wrapper_xcursor)(const char*, int);
-XcursorImages* (*XcursorFilenameLoadImages_dylibloader_wrapper_xcursor)(const char*, int);
-XcursorImages* (*XcursorFilenameLoadAllImages_dylibloader_wrapper_xcursor)(const char*);
-XcursorBool (*XcursorFilenameLoad_dylibloader_wrapper_xcursor)(const char*, XcursorComments**, XcursorImages**);
-XcursorBool (*XcursorFilenameSaveImages_dylibloader_wrapper_xcursor)(const char*,const XcursorImages*);
-XcursorBool (*XcursorFilenameSave_dylibloader_wrapper_xcursor)(const char*,const XcursorComments*,const XcursorImages*);
-XcursorImage* (*XcursorLibraryLoadImage_dylibloader_wrapper_xcursor)(const char*,const char*, int);
-XcursorImages* (*XcursorLibraryLoadImages_dylibloader_wrapper_xcursor)(const char*,const char*, int);
-const char* (*XcursorLibraryPath_dylibloader_wrapper_xcursor)( void);
-int (*XcursorLibraryShape_dylibloader_wrapper_xcursor)(const char*);
-Cursor (*XcursorImageLoadCursor_dylibloader_wrapper_xcursor)( Display*,const XcursorImage*);
-XcursorCursors* (*XcursorImagesLoadCursors_dylibloader_wrapper_xcursor)( Display*,const XcursorImages*);
-Cursor (*XcursorImagesLoadCursor_dylibloader_wrapper_xcursor)( Display*,const XcursorImages*);
-Cursor (*XcursorFilenameLoadCursor_dylibloader_wrapper_xcursor)( Display*,const char*);
-XcursorCursors* (*XcursorFilenameLoadCursors_dylibloader_wrapper_xcursor)( Display*,const char*);
-Cursor (*XcursorLibraryLoadCursor_dylibloader_wrapper_xcursor)( Display*,const char*);
-XcursorCursors* (*XcursorLibraryLoadCursors_dylibloader_wrapper_xcursor)( Display*,const char*);
-XcursorImage* (*XcursorShapeLoadImage_dylibloader_wrapper_xcursor)( unsigned int,const char*, int);
-XcursorImages* (*XcursorShapeLoadImages_dylibloader_wrapper_xcursor)( unsigned int,const char*, int);
-Cursor (*XcursorShapeLoadCursor_dylibloader_wrapper_xcursor)( Display*, unsigned int);
-XcursorCursors* (*XcursorShapeLoadCursors_dylibloader_wrapper_xcursor)( Display*, unsigned int);
-Cursor (*XcursorTryShapeCursor_dylibloader_wrapper_xcursor)( Display*, Font, Font, unsigned int, unsigned int,const XColor*,const XColor*);
-void (*XcursorNoticeCreateBitmap_dylibloader_wrapper_xcursor)( Display*, Pixmap, unsigned int, unsigned int);
-void (*XcursorNoticePutBitmap_dylibloader_wrapper_xcursor)( Display*, Drawable, XImage*);
-Cursor (*XcursorTryShapeBitmapCursor_dylibloader_wrapper_xcursor)( Display*, Pixmap, Pixmap, XColor*, XColor*, unsigned int, unsigned int);
-void (*XcursorImageHash_dylibloader_wrapper_xcursor)( XImage*, unsigned char [16]);
-XcursorBool (*XcursorSupportsARGB_dylibloader_wrapper_xcursor)( Display*);
-XcursorBool (*XcursorSupportsAnim_dylibloader_wrapper_xcursor)( Display*);
-XcursorBool (*XcursorSetDefaultSize_dylibloader_wrapper_xcursor)( Display*, int);
-int (*XcursorGetDefaultSize_dylibloader_wrapper_xcursor)( Display*);
-XcursorBool (*XcursorSetTheme_dylibloader_wrapper_xcursor)( Display*,const char*);
-char* (*XcursorGetTheme_dylibloader_wrapper_xcursor)( Display*);
-XcursorBool (*XcursorGetThemeCore_dylibloader_wrapper_xcursor)( Display*);
-XcursorBool (*XcursorSetThemeCore_dylibloader_wrapper_xcursor)( Display*, XcursorBool);
+XcursorImage *(*XcursorImageCreate_dylibloader_wrapper_xcursor)(int, int);
+void (*XcursorImageDestroy_dylibloader_wrapper_xcursor)(XcursorImage *);
+XcursorImages *(*XcursorImagesCreate_dylibloader_wrapper_xcursor)(int);
+void (*XcursorImagesDestroy_dylibloader_wrapper_xcursor)(XcursorImages *);
+void (*XcursorImagesSetName_dylibloader_wrapper_xcursor)(XcursorImages *, const char *);
+XcursorCursors *(*XcursorCursorsCreate_dylibloader_wrapper_xcursor)(Display *, int);
+void (*XcursorCursorsDestroy_dylibloader_wrapper_xcursor)(XcursorCursors *);
+XcursorAnimate *(*XcursorAnimateCreate_dylibloader_wrapper_xcursor)(XcursorCursors *);
+void (*XcursorAnimateDestroy_dylibloader_wrapper_xcursor)(XcursorAnimate *);
+Cursor (*XcursorAnimateNext_dylibloader_wrapper_xcursor)(XcursorAnimate *);
+XcursorComment *(*XcursorCommentCreate_dylibloader_wrapper_xcursor)(XcursorUInt, int);
+void (*XcursorCommentDestroy_dylibloader_wrapper_xcursor)(XcursorComment *);
+XcursorComments *(*XcursorCommentsCreate_dylibloader_wrapper_xcursor)(int);
+void (*XcursorCommentsDestroy_dylibloader_wrapper_xcursor)(XcursorComments *);
+XcursorImage *(*XcursorXcFileLoadImage_dylibloader_wrapper_xcursor)(XcursorFile *, int);
+XcursorImages *(*XcursorXcFileLoadImages_dylibloader_wrapper_xcursor)(XcursorFile *, int);
+XcursorImages *(*XcursorXcFileLoadAllImages_dylibloader_wrapper_xcursor)(XcursorFile *);
+XcursorBool (*XcursorXcFileLoad_dylibloader_wrapper_xcursor)(XcursorFile *, XcursorComments **, XcursorImages **);
+XcursorBool (*XcursorXcFileSave_dylibloader_wrapper_xcursor)(XcursorFile *, const XcursorComments *, const XcursorImages *);
+XcursorImage *(*XcursorFileLoadImage_dylibloader_wrapper_xcursor)(FILE *, int);
+XcursorImages *(*XcursorFileLoadImages_dylibloader_wrapper_xcursor)(FILE *, int);
+XcursorImages *(*XcursorFileLoadAllImages_dylibloader_wrapper_xcursor)(FILE *);
+XcursorBool (*XcursorFileLoad_dylibloader_wrapper_xcursor)(FILE *, XcursorComments **, XcursorImages **);
+XcursorBool (*XcursorFileSaveImages_dylibloader_wrapper_xcursor)(FILE *, const XcursorImages *);
+XcursorBool (*XcursorFileSave_dylibloader_wrapper_xcursor)(FILE *, const XcursorComments *, const XcursorImages *);
+XcursorImage *(*XcursorFilenameLoadImage_dylibloader_wrapper_xcursor)(const char *, int);
+XcursorImages *(*XcursorFilenameLoadImages_dylibloader_wrapper_xcursor)(const char *, int);
+XcursorImages *(*XcursorFilenameLoadAllImages_dylibloader_wrapper_xcursor)(const char *);
+XcursorBool (*XcursorFilenameLoad_dylibloader_wrapper_xcursor)(const char *, XcursorComments **, XcursorImages **);
+XcursorBool (*XcursorFilenameSaveImages_dylibloader_wrapper_xcursor)(const char *, const XcursorImages *);
+XcursorBool (*XcursorFilenameSave_dylibloader_wrapper_xcursor)(const char *, const XcursorComments *, const XcursorImages *);
+XcursorImage *(*XcursorLibraryLoadImage_dylibloader_wrapper_xcursor)(const char *, const char *, int);
+XcursorImages *(*XcursorLibraryLoadImages_dylibloader_wrapper_xcursor)(const char *, const char *, int);
+const char *(*XcursorLibraryPath_dylibloader_wrapper_xcursor)(void);
+int (*XcursorLibraryShape_dylibloader_wrapper_xcursor)(const char *);
+Cursor (*XcursorImageLoadCursor_dylibloader_wrapper_xcursor)(Display *, const XcursorImage *);
+XcursorCursors *(*XcursorImagesLoadCursors_dylibloader_wrapper_xcursor)(Display *, const XcursorImages *);
+Cursor (*XcursorImagesLoadCursor_dylibloader_wrapper_xcursor)(Display *, const XcursorImages *);
+Cursor (*XcursorFilenameLoadCursor_dylibloader_wrapper_xcursor)(Display *, const char *);
+XcursorCursors *(*XcursorFilenameLoadCursors_dylibloader_wrapper_xcursor)(Display *, const char *);
+Cursor (*XcursorLibraryLoadCursor_dylibloader_wrapper_xcursor)(Display *, const char *);
+XcursorCursors *(*XcursorLibraryLoadCursors_dylibloader_wrapper_xcursor)(Display *, const char *);
+XcursorImage *(*XcursorShapeLoadImage_dylibloader_wrapper_xcursor)(unsigned int, const char *, int);
+XcursorImages *(*XcursorShapeLoadImages_dylibloader_wrapper_xcursor)(unsigned int, const char *, int);
+Cursor (*XcursorShapeLoadCursor_dylibloader_wrapper_xcursor)(Display *, unsigned int);
+XcursorCursors *(*XcursorShapeLoadCursors_dylibloader_wrapper_xcursor)(Display *, unsigned int);
+Cursor (*XcursorTryShapeCursor_dylibloader_wrapper_xcursor)(Display *, Font, Font, unsigned int, unsigned int, const XColor *, const XColor *);
+void (*XcursorNoticeCreateBitmap_dylibloader_wrapper_xcursor)(Display *, Pixmap, unsigned int, unsigned int);
+void (*XcursorNoticePutBitmap_dylibloader_wrapper_xcursor)(Display *, Drawable, XImage *);
+Cursor (*XcursorTryShapeBitmapCursor_dylibloader_wrapper_xcursor)(Display *, Pixmap, Pixmap, XColor *, XColor *, unsigned int, unsigned int);
+void (*XcursorImageHash_dylibloader_wrapper_xcursor)(XImage *, unsigned char [16]);
+XcursorBool (*XcursorSupportsARGB_dylibloader_wrapper_xcursor)(Display *);
+XcursorBool (*XcursorSupportsAnim_dylibloader_wrapper_xcursor)(Display *);
+XcursorBool (*XcursorSetDefaultSize_dylibloader_wrapper_xcursor)(Display *, int);
+int (*XcursorGetDefaultSize_dylibloader_wrapper_xcursor)(Display *);
+XcursorBool (*XcursorSetTheme_dylibloader_wrapper_xcursor)(Display *, const char *);
+char *(*XcursorGetTheme_dylibloader_wrapper_xcursor)(Display *);
+XcursorBool (*XcursorGetThemeCore_dylibloader_wrapper_xcursor)(Display *);
+XcursorBool (*XcursorSetThemeCore_dylibloader_wrapper_xcursor)(Display *, XcursorBool);
int initialize_xcursor(int verbose) {
void *handle;
char *error;
diff --git a/platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.h b/platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.h
index 9f8d8bbca2..7266cfe609 100644
--- a/platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.h
+++ b/platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.h
@@ -2,13 +2,9 @@
#define DYLIBLOAD_WRAPPER_XCURSOR
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
-// generated by generate-wrapper.py 0.3 on 2023-01-23 15:09:53
-// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/Xcursor/Xcursor.h --sys-include "thirdparty/linuxbsd_headers/X11/Xcursor/Xcursor.h" --soname libXcursor.so.1 --init-name xcursor --output-header ./platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.c
+// generated by generate-wrapper.py 0.6 on 2024-11-09 02:52:36
+// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/Xcursor/Xcursor.h --sys-include thirdparty/linuxbsd_headers/X11/Xcursor/Xcursor.h --soname libXcursor.so.1 --init-name xcursor --output-header ./platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xcursor-so_wrap.c --ignore-other
//
-// NOTE: Generated from Xcursor 1.2.0.
-// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existent symbols inherited from
-// libX11, but absent in libXcursor.so.1, were removed.
#include <stdint.h>
#define XcursorImageCreate XcursorImageCreate_dylibloader_orig_xcursor
@@ -192,65 +188,65 @@ extern "C" {
#define XcursorGetTheme XcursorGetTheme_dylibloader_wrapper_xcursor
#define XcursorGetThemeCore XcursorGetThemeCore_dylibloader_wrapper_xcursor
#define XcursorSetThemeCore XcursorSetThemeCore_dylibloader_wrapper_xcursor
-extern XcursorImage* (*XcursorImageCreate_dylibloader_wrapper_xcursor)( int, int);
-extern void (*XcursorImageDestroy_dylibloader_wrapper_xcursor)( XcursorImage*);
-extern XcursorImages* (*XcursorImagesCreate_dylibloader_wrapper_xcursor)( int);
-extern void (*XcursorImagesDestroy_dylibloader_wrapper_xcursor)( XcursorImages*);
-extern void (*XcursorImagesSetName_dylibloader_wrapper_xcursor)( XcursorImages*,const char*);
-extern XcursorCursors* (*XcursorCursorsCreate_dylibloader_wrapper_xcursor)( Display*, int);
-extern void (*XcursorCursorsDestroy_dylibloader_wrapper_xcursor)( XcursorCursors*);
-extern XcursorAnimate* (*XcursorAnimateCreate_dylibloader_wrapper_xcursor)( XcursorCursors*);
-extern void (*XcursorAnimateDestroy_dylibloader_wrapper_xcursor)( XcursorAnimate*);
-extern Cursor (*XcursorAnimateNext_dylibloader_wrapper_xcursor)( XcursorAnimate*);
-extern XcursorComment* (*XcursorCommentCreate_dylibloader_wrapper_xcursor)( XcursorUInt, int);
-extern void (*XcursorCommentDestroy_dylibloader_wrapper_xcursor)( XcursorComment*);
-extern XcursorComments* (*XcursorCommentsCreate_dylibloader_wrapper_xcursor)( int);
-extern void (*XcursorCommentsDestroy_dylibloader_wrapper_xcursor)( XcursorComments*);
-extern XcursorImage* (*XcursorXcFileLoadImage_dylibloader_wrapper_xcursor)( XcursorFile*, int);
-extern XcursorImages* (*XcursorXcFileLoadImages_dylibloader_wrapper_xcursor)( XcursorFile*, int);
-extern XcursorImages* (*XcursorXcFileLoadAllImages_dylibloader_wrapper_xcursor)( XcursorFile*);
-extern XcursorBool (*XcursorXcFileLoad_dylibloader_wrapper_xcursor)( XcursorFile*, XcursorComments**, XcursorImages**);
-extern XcursorBool (*XcursorXcFileSave_dylibloader_wrapper_xcursor)( XcursorFile*,const XcursorComments*,const XcursorImages*);
-extern XcursorImage* (*XcursorFileLoadImage_dylibloader_wrapper_xcursor)( FILE*, int);
-extern XcursorImages* (*XcursorFileLoadImages_dylibloader_wrapper_xcursor)( FILE*, int);
-extern XcursorImages* (*XcursorFileLoadAllImages_dylibloader_wrapper_xcursor)( FILE*);
-extern XcursorBool (*XcursorFileLoad_dylibloader_wrapper_xcursor)( FILE*, XcursorComments**, XcursorImages**);
-extern XcursorBool (*XcursorFileSaveImages_dylibloader_wrapper_xcursor)( FILE*,const XcursorImages*);
-extern XcursorBool (*XcursorFileSave_dylibloader_wrapper_xcursor)( FILE*,const XcursorComments*,const XcursorImages*);
-extern XcursorImage* (*XcursorFilenameLoadImage_dylibloader_wrapper_xcursor)(const char*, int);
-extern XcursorImages* (*XcursorFilenameLoadImages_dylibloader_wrapper_xcursor)(const char*, int);
-extern XcursorImages* (*XcursorFilenameLoadAllImages_dylibloader_wrapper_xcursor)(const char*);
-extern XcursorBool (*XcursorFilenameLoad_dylibloader_wrapper_xcursor)(const char*, XcursorComments**, XcursorImages**);
-extern XcursorBool (*XcursorFilenameSaveImages_dylibloader_wrapper_xcursor)(const char*,const XcursorImages*);
-extern XcursorBool (*XcursorFilenameSave_dylibloader_wrapper_xcursor)(const char*,const XcursorComments*,const XcursorImages*);
-extern XcursorImage* (*XcursorLibraryLoadImage_dylibloader_wrapper_xcursor)(const char*,const char*, int);
-extern XcursorImages* (*XcursorLibraryLoadImages_dylibloader_wrapper_xcursor)(const char*,const char*, int);
-extern const char* (*XcursorLibraryPath_dylibloader_wrapper_xcursor)( void);
-extern int (*XcursorLibraryShape_dylibloader_wrapper_xcursor)(const char*);
-extern Cursor (*XcursorImageLoadCursor_dylibloader_wrapper_xcursor)( Display*,const XcursorImage*);
-extern XcursorCursors* (*XcursorImagesLoadCursors_dylibloader_wrapper_xcursor)( Display*,const XcursorImages*);
-extern Cursor (*XcursorImagesLoadCursor_dylibloader_wrapper_xcursor)( Display*,const XcursorImages*);
-extern Cursor (*XcursorFilenameLoadCursor_dylibloader_wrapper_xcursor)( Display*,const char*);
-extern XcursorCursors* (*XcursorFilenameLoadCursors_dylibloader_wrapper_xcursor)( Display*,const char*);
-extern Cursor (*XcursorLibraryLoadCursor_dylibloader_wrapper_xcursor)( Display*,const char*);
-extern XcursorCursors* (*XcursorLibraryLoadCursors_dylibloader_wrapper_xcursor)( Display*,const char*);
-extern XcursorImage* (*XcursorShapeLoadImage_dylibloader_wrapper_xcursor)( unsigned int,const char*, int);
-extern XcursorImages* (*XcursorShapeLoadImages_dylibloader_wrapper_xcursor)( unsigned int,const char*, int);
-extern Cursor (*XcursorShapeLoadCursor_dylibloader_wrapper_xcursor)( Display*, unsigned int);
-extern XcursorCursors* (*XcursorShapeLoadCursors_dylibloader_wrapper_xcursor)( Display*, unsigned int);
-extern Cursor (*XcursorTryShapeCursor_dylibloader_wrapper_xcursor)( Display*, Font, Font, unsigned int, unsigned int,const XColor*,const XColor*);
-extern void (*XcursorNoticeCreateBitmap_dylibloader_wrapper_xcursor)( Display*, Pixmap, unsigned int, unsigned int);
-extern void (*XcursorNoticePutBitmap_dylibloader_wrapper_xcursor)( Display*, Drawable, XImage*);
-extern Cursor (*XcursorTryShapeBitmapCursor_dylibloader_wrapper_xcursor)( Display*, Pixmap, Pixmap, XColor*, XColor*, unsigned int, unsigned int);
-extern void (*XcursorImageHash_dylibloader_wrapper_xcursor)( XImage*, unsigned char [16]);
-extern XcursorBool (*XcursorSupportsARGB_dylibloader_wrapper_xcursor)( Display*);
-extern XcursorBool (*XcursorSupportsAnim_dylibloader_wrapper_xcursor)( Display*);
-extern XcursorBool (*XcursorSetDefaultSize_dylibloader_wrapper_xcursor)( Display*, int);
-extern int (*XcursorGetDefaultSize_dylibloader_wrapper_xcursor)( Display*);
-extern XcursorBool (*XcursorSetTheme_dylibloader_wrapper_xcursor)( Display*,const char*);
-extern char* (*XcursorGetTheme_dylibloader_wrapper_xcursor)( Display*);
-extern XcursorBool (*XcursorGetThemeCore_dylibloader_wrapper_xcursor)( Display*);
-extern XcursorBool (*XcursorSetThemeCore_dylibloader_wrapper_xcursor)( Display*, XcursorBool);
+extern XcursorImage *(*XcursorImageCreate_dylibloader_wrapper_xcursor)(int, int);
+extern void (*XcursorImageDestroy_dylibloader_wrapper_xcursor)(XcursorImage *);
+extern XcursorImages *(*XcursorImagesCreate_dylibloader_wrapper_xcursor)(int);
+extern void (*XcursorImagesDestroy_dylibloader_wrapper_xcursor)(XcursorImages *);
+extern void (*XcursorImagesSetName_dylibloader_wrapper_xcursor)(XcursorImages *, const char *);
+extern XcursorCursors *(*XcursorCursorsCreate_dylibloader_wrapper_xcursor)(Display *, int);
+extern void (*XcursorCursorsDestroy_dylibloader_wrapper_xcursor)(XcursorCursors *);
+extern XcursorAnimate *(*XcursorAnimateCreate_dylibloader_wrapper_xcursor)(XcursorCursors *);
+extern void (*XcursorAnimateDestroy_dylibloader_wrapper_xcursor)(XcursorAnimate *);
+extern Cursor (*XcursorAnimateNext_dylibloader_wrapper_xcursor)(XcursorAnimate *);
+extern XcursorComment *(*XcursorCommentCreate_dylibloader_wrapper_xcursor)(XcursorUInt, int);
+extern void (*XcursorCommentDestroy_dylibloader_wrapper_xcursor)(XcursorComment *);
+extern XcursorComments *(*XcursorCommentsCreate_dylibloader_wrapper_xcursor)(int);
+extern void (*XcursorCommentsDestroy_dylibloader_wrapper_xcursor)(XcursorComments *);
+extern XcursorImage *(*XcursorXcFileLoadImage_dylibloader_wrapper_xcursor)(XcursorFile *, int);
+extern XcursorImages *(*XcursorXcFileLoadImages_dylibloader_wrapper_xcursor)(XcursorFile *, int);
+extern XcursorImages *(*XcursorXcFileLoadAllImages_dylibloader_wrapper_xcursor)(XcursorFile *);
+extern XcursorBool (*XcursorXcFileLoad_dylibloader_wrapper_xcursor)(XcursorFile *, XcursorComments **, XcursorImages **);
+extern XcursorBool (*XcursorXcFileSave_dylibloader_wrapper_xcursor)(XcursorFile *, const XcursorComments *, const XcursorImages *);
+extern XcursorImage *(*XcursorFileLoadImage_dylibloader_wrapper_xcursor)(FILE *, int);
+extern XcursorImages *(*XcursorFileLoadImages_dylibloader_wrapper_xcursor)(FILE *, int);
+extern XcursorImages *(*XcursorFileLoadAllImages_dylibloader_wrapper_xcursor)(FILE *);
+extern XcursorBool (*XcursorFileLoad_dylibloader_wrapper_xcursor)(FILE *, XcursorComments **, XcursorImages **);
+extern XcursorBool (*XcursorFileSaveImages_dylibloader_wrapper_xcursor)(FILE *, const XcursorImages *);
+extern XcursorBool (*XcursorFileSave_dylibloader_wrapper_xcursor)(FILE *, const XcursorComments *, const XcursorImages *);
+extern XcursorImage *(*XcursorFilenameLoadImage_dylibloader_wrapper_xcursor)(const char *, int);
+extern XcursorImages *(*XcursorFilenameLoadImages_dylibloader_wrapper_xcursor)(const char *, int);
+extern XcursorImages *(*XcursorFilenameLoadAllImages_dylibloader_wrapper_xcursor)(const char *);
+extern XcursorBool (*XcursorFilenameLoad_dylibloader_wrapper_xcursor)(const char *, XcursorComments **, XcursorImages **);
+extern XcursorBool (*XcursorFilenameSaveImages_dylibloader_wrapper_xcursor)(const char *, const XcursorImages *);
+extern XcursorBool (*XcursorFilenameSave_dylibloader_wrapper_xcursor)(const char *, const XcursorComments *, const XcursorImages *);
+extern XcursorImage *(*XcursorLibraryLoadImage_dylibloader_wrapper_xcursor)(const char *, const char *, int);
+extern XcursorImages *(*XcursorLibraryLoadImages_dylibloader_wrapper_xcursor)(const char *, const char *, int);
+extern const char *(*XcursorLibraryPath_dylibloader_wrapper_xcursor)(void);
+extern int (*XcursorLibraryShape_dylibloader_wrapper_xcursor)(const char *);
+extern Cursor (*XcursorImageLoadCursor_dylibloader_wrapper_xcursor)(Display *, const XcursorImage *);
+extern XcursorCursors *(*XcursorImagesLoadCursors_dylibloader_wrapper_xcursor)(Display *, const XcursorImages *);
+extern Cursor (*XcursorImagesLoadCursor_dylibloader_wrapper_xcursor)(Display *, const XcursorImages *);
+extern Cursor (*XcursorFilenameLoadCursor_dylibloader_wrapper_xcursor)(Display *, const char *);
+extern XcursorCursors *(*XcursorFilenameLoadCursors_dylibloader_wrapper_xcursor)(Display *, const char *);
+extern Cursor (*XcursorLibraryLoadCursor_dylibloader_wrapper_xcursor)(Display *, const char *);
+extern XcursorCursors *(*XcursorLibraryLoadCursors_dylibloader_wrapper_xcursor)(Display *, const char *);
+extern XcursorImage *(*XcursorShapeLoadImage_dylibloader_wrapper_xcursor)(unsigned int, const char *, int);
+extern XcursorImages *(*XcursorShapeLoadImages_dylibloader_wrapper_xcursor)(unsigned int, const char *, int);
+extern Cursor (*XcursorShapeLoadCursor_dylibloader_wrapper_xcursor)(Display *, unsigned int);
+extern XcursorCursors *(*XcursorShapeLoadCursors_dylibloader_wrapper_xcursor)(Display *, unsigned int);
+extern Cursor (*XcursorTryShapeCursor_dylibloader_wrapper_xcursor)(Display *, Font, Font, unsigned int, unsigned int, const XColor *, const XColor *);
+extern void (*XcursorNoticeCreateBitmap_dylibloader_wrapper_xcursor)(Display *, Pixmap, unsigned int, unsigned int);
+extern void (*XcursorNoticePutBitmap_dylibloader_wrapper_xcursor)(Display *, Drawable, XImage *);
+extern Cursor (*XcursorTryShapeBitmapCursor_dylibloader_wrapper_xcursor)(Display *, Pixmap, Pixmap, XColor *, XColor *, unsigned int, unsigned int);
+extern void (*XcursorImageHash_dylibloader_wrapper_xcursor)(XImage *, unsigned char [16]);
+extern XcursorBool (*XcursorSupportsARGB_dylibloader_wrapper_xcursor)(Display *);
+extern XcursorBool (*XcursorSupportsAnim_dylibloader_wrapper_xcursor)(Display *);
+extern XcursorBool (*XcursorSetDefaultSize_dylibloader_wrapper_xcursor)(Display *, int);
+extern int (*XcursorGetDefaultSize_dylibloader_wrapper_xcursor)(Display *);
+extern XcursorBool (*XcursorSetTheme_dylibloader_wrapper_xcursor)(Display *, const char *);
+extern char *(*XcursorGetTheme_dylibloader_wrapper_xcursor)(Display *);
+extern XcursorBool (*XcursorGetThemeCore_dylibloader_wrapper_xcursor)(Display *);
+extern XcursorBool (*XcursorSetThemeCore_dylibloader_wrapper_xcursor)(Display *, XcursorBool);
int initialize_xcursor(int verbose);
#ifdef __cplusplus
}
diff --git a/platform/linuxbsd/x11/dynwrappers/xext-so_wrap.c b/platform/linuxbsd/x11/dynwrappers/xext-so_wrap.c
index 4e3349c574..56ae854686 100644
--- a/platform/linuxbsd/x11/dynwrappers/xext-so_wrap.c
+++ b/platform/linuxbsd/x11/dynwrappers/xext-so_wrap.c
@@ -1,19 +1,11 @@
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
-// generated by generate-wrapper.py 0.3 on 2023-01-23 15:11:29
-// flags: generate-wrapper.py --sys-include "thirdparty/linuxbsd_headers/X11/extensions/Xext.h" --include ./thirdparty/linuxbsd_headers/X11/extensions/shape.h --sys-include "thirdparty/linuxbsd_headers/X11/extensions/shape.h" --soname libXext.so.6 --init-name xext --output-header ./platform/linuxbsd/x11/dynwrappers/xext-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xext-so_wrap.c
+// generated by generate-wrapper.py 0.6 on 2024-11-09 02:52:36
+// flags: generate-wrapper.py --sys-include thirdparty/linuxbsd_headers/X11/extensions/Xext.h --include ./thirdparty/linuxbsd_headers/X11/extensions/shape.h --sys-include thirdparty/linuxbsd_headers/X11/extensions/shape.h --soname libXext.so.6 --init-name xext --output-header ./platform/linuxbsd/x11/dynwrappers/xext-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xext-so_wrap.c --ignore-other --implementation-header thirdparty/linuxbsd_headers/X11/Xlib.h
//
-// NOTE: Generated from Xext 1.3.5.
-// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existent symbols inherited from
-// libX11, but absent in libXext.so.6, were removed and an include needed for
-// proper parsing was added (this had also to be temporarily added to the
-// original header, as dynload-wrapper would complain otherwise)
#include <stdint.h>
-// HANDPATCH: Needed for a successful compilation.
#include "thirdparty/linuxbsd_headers/X11/Xlib.h"
-
#define XShapeQueryExtension XShapeQueryExtension_dylibloader_orig_xext
#define XShapeQueryVersion XShapeQueryVersion_dylibloader_orig_xext
#define XShapeCombineRegion XShapeCombineRegion_dylibloader_orig_xext
@@ -40,17 +32,17 @@
#undef XShapeGetRectangles
#include <dlfcn.h>
#include <stdio.h>
-int (*XShapeQueryExtension_dylibloader_wrapper_xext)( Display*, int*, int*);
-int (*XShapeQueryVersion_dylibloader_wrapper_xext)( Display*, int*, int*);
-void (*XShapeCombineRegion_dylibloader_wrapper_xext)( Display*, Window, int, int, int, Region, int);
-void (*XShapeCombineRectangles_dylibloader_wrapper_xext)( Display*, Window, int, int, int, XRectangle*, int, int, int);
-void (*XShapeCombineMask_dylibloader_wrapper_xext)( Display*, Window, int, int, int, Pixmap, int);
-void (*XShapeCombineShape_dylibloader_wrapper_xext)( Display*, Window, int, int, int, Window, int, int);
-void (*XShapeOffsetShape_dylibloader_wrapper_xext)( Display*, Window, int, int, int);
-int (*XShapeQueryExtents_dylibloader_wrapper_xext)( Display*, Window, int*, int*, int*, unsigned int*, unsigned int*, int*, int*, int*, unsigned int*, unsigned int*);
-void (*XShapeSelectInput_dylibloader_wrapper_xext)( Display*, Window, unsigned long);
-unsigned long (*XShapeInputSelected_dylibloader_wrapper_xext)( Display*, Window);
-XRectangle* (*XShapeGetRectangles_dylibloader_wrapper_xext)( Display*, Window, int, int*, int*);
+int (*XShapeQueryExtension_dylibloader_wrapper_xext)(Display *, int *, int *);
+int (*XShapeQueryVersion_dylibloader_wrapper_xext)(Display *, int *, int *);
+void (*XShapeCombineRegion_dylibloader_wrapper_xext)(Display *, Window, int, int, int, Region, int);
+void (*XShapeCombineRectangles_dylibloader_wrapper_xext)(Display *, Window, int, int, int, XRectangle *, int, int, int);
+void (*XShapeCombineMask_dylibloader_wrapper_xext)(Display *, Window, int, int, int, Pixmap, int);
+void (*XShapeCombineShape_dylibloader_wrapper_xext)(Display *, Window, int, int, int, Window, int, int);
+void (*XShapeOffsetShape_dylibloader_wrapper_xext)(Display *, Window, int, int, int);
+int (*XShapeQueryExtents_dylibloader_wrapper_xext)(Display *, Window, int *, int *, int *, unsigned int *, unsigned int *, int *, int *, int *, unsigned int *, unsigned int *);
+void (*XShapeSelectInput_dylibloader_wrapper_xext)(Display *, Window, unsigned long);
+unsigned long (*XShapeInputSelected_dylibloader_wrapper_xext)(Display *, Window);
+XRectangle *(*XShapeGetRectangles_dylibloader_wrapper_xext)(Display *, Window, int, int *, int *);
int initialize_xext(int verbose) {
void *handle;
char *error;
diff --git a/platform/linuxbsd/x11/dynwrappers/xext-so_wrap.h b/platform/linuxbsd/x11/dynwrappers/xext-so_wrap.h
index e535756d82..ecce399d09 100644
--- a/platform/linuxbsd/x11/dynwrappers/xext-so_wrap.h
+++ b/platform/linuxbsd/x11/dynwrappers/xext-so_wrap.h
@@ -2,20 +2,11 @@
#define DYLIBLOAD_WRAPPER_XEXT
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
-// generated by generate-wrapper.py 0.3 on 2023-01-23 15:11:29
-// flags: generate-wrapper.py --sys-include "thirdparty/linuxbsd_headers/X11/extensions/Xext.h" --include ./thirdparty/linuxbsd_headers/X11/extensions/shape.h --sys-include "thirdparty/linuxbsd_headers/X11/extensions/shape.h" --soname libXext.so.6 --init-name xext --output-header ./platform/linuxbsd/x11/dynwrappers/xext-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xext-so_wrap.c
+// generated by generate-wrapper.py 0.6 on 2024-11-09 02:52:36
+// flags: generate-wrapper.py --sys-include thirdparty/linuxbsd_headers/X11/extensions/Xext.h --include ./thirdparty/linuxbsd_headers/X11/extensions/shape.h --sys-include thirdparty/linuxbsd_headers/X11/extensions/shape.h --soname libXext.so.6 --init-name xext --output-header ./platform/linuxbsd/x11/dynwrappers/xext-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xext-so_wrap.c --ignore-other --implementation-header thirdparty/linuxbsd_headers/X11/Xlib.h
//
-// NOTE: Generated from Xext 1.3.5.
-// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existent symbols inherited from
-// libX11, but absent in libXext.so.6, were removed and an include needed for
-// proper parsing was added (this had also to be temporarily added to the
-// original header, as dynload-wrapper would complain otherwise)
#include <stdint.h>
-// HANDPATCH: Needed for a successful compilation.
-#include "thirdparty/linuxbsd_headers/X11/Xlib.h"
-
#define XShapeQueryExtension XShapeQueryExtension_dylibloader_orig_xext
#define XShapeQueryVersion XShapeQueryVersion_dylibloader_orig_xext
#define XShapeCombineRegion XShapeCombineRegion_dylibloader_orig_xext
@@ -54,17 +45,17 @@ extern "C" {
#define XShapeSelectInput XShapeSelectInput_dylibloader_wrapper_xext
#define XShapeInputSelected XShapeInputSelected_dylibloader_wrapper_xext
#define XShapeGetRectangles XShapeGetRectangles_dylibloader_wrapper_xext
-extern int (*XShapeQueryExtension_dylibloader_wrapper_xext)( Display*, int*, int*);
-extern int (*XShapeQueryVersion_dylibloader_wrapper_xext)( Display*, int*, int*);
-extern void (*XShapeCombineRegion_dylibloader_wrapper_xext)( Display*, Window, int, int, int, Region, int);
-extern void (*XShapeCombineRectangles_dylibloader_wrapper_xext)( Display*, Window, int, int, int, XRectangle*, int, int, int);
-extern void (*XShapeCombineMask_dylibloader_wrapper_xext)( Display*, Window, int, int, int, Pixmap, int);
-extern void (*XShapeCombineShape_dylibloader_wrapper_xext)( Display*, Window, int, int, int, Window, int, int);
-extern void (*XShapeOffsetShape_dylibloader_wrapper_xext)( Display*, Window, int, int, int);
-extern int (*XShapeQueryExtents_dylibloader_wrapper_xext)( Display*, Window, int*, int*, int*, unsigned int*, unsigned int*, int*, int*, int*, unsigned int*, unsigned int*);
-extern void (*XShapeSelectInput_dylibloader_wrapper_xext)( Display*, Window, unsigned long);
-extern unsigned long (*XShapeInputSelected_dylibloader_wrapper_xext)( Display*, Window);
-extern XRectangle* (*XShapeGetRectangles_dylibloader_wrapper_xext)( Display*, Window, int, int*, int*);
+extern int (*XShapeQueryExtension_dylibloader_wrapper_xext)(Display *, int *, int *);
+extern int (*XShapeQueryVersion_dylibloader_wrapper_xext)(Display *, int *, int *);
+extern void (*XShapeCombineRegion_dylibloader_wrapper_xext)(Display *, Window, int, int, int, Region, int);
+extern void (*XShapeCombineRectangles_dylibloader_wrapper_xext)(Display *, Window, int, int, int, XRectangle *, int, int, int);
+extern void (*XShapeCombineMask_dylibloader_wrapper_xext)(Display *, Window, int, int, int, Pixmap, int);
+extern void (*XShapeCombineShape_dylibloader_wrapper_xext)(Display *, Window, int, int, int, Window, int, int);
+extern void (*XShapeOffsetShape_dylibloader_wrapper_xext)(Display *, Window, int, int, int);
+extern int (*XShapeQueryExtents_dylibloader_wrapper_xext)(Display *, Window, int *, int *, int *, unsigned int *, unsigned int *, int *, int *, int *, unsigned int *, unsigned int *);
+extern void (*XShapeSelectInput_dylibloader_wrapper_xext)(Display *, Window, unsigned long);
+extern unsigned long (*XShapeInputSelected_dylibloader_wrapper_xext)(Display *, Window);
+extern XRectangle *(*XShapeGetRectangles_dylibloader_wrapper_xext)(Display *, Window, int, int *, int *);
int initialize_xext(int verbose);
#ifdef __cplusplus
}
diff --git a/platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.c b/platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.c
index 850ed1fc6b..eeb6bf7a8f 100644
--- a/platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.c
+++ b/platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.c
@@ -1,12 +1,8 @@
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
-// generated by generate-wrapper.py 0.3 on 2023-01-23 15:11:35
-// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/extensions/Xinerama.h --sys-include "thirdparty/linuxbsd_headers/X11/extensions/Xinerama.h" --soname libXinerama.so.1 --init-name xinerama --output-header ./platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.c
+// generated by generate-wrapper.py 0.6 on 2024-11-09 02:52:36
+// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/extensions/Xinerama.h --sys-include thirdparty/linuxbsd_headers/X11/extensions/Xinerama.h --soname libXinerama.so.1 --init-name xinerama --output-header ./platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.c --ignore-other
//
-// NOTE: Generated from Xinerama 1.1.4.
-// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existent symbols inherited from
-// libX11, but absent in libXinerama.so.1, were removed.
#include <stdint.h>
#define XineramaQueryExtension XineramaQueryExtension_dylibloader_orig_xinerama
@@ -20,10 +16,10 @@
#undef XineramaQueryScreens
#include <dlfcn.h>
#include <stdio.h>
-int (*XineramaQueryExtension_dylibloader_wrapper_xinerama)( Display*, int*, int*);
-int (*XineramaQueryVersion_dylibloader_wrapper_xinerama)( Display*, int*, int*);
-int (*XineramaIsActive_dylibloader_wrapper_xinerama)( Display*);
-XineramaScreenInfo* (*XineramaQueryScreens_dylibloader_wrapper_xinerama)( Display*, int*);
+int (*XineramaQueryExtension_dylibloader_wrapper_xinerama)(Display *, int *, int *);
+int (*XineramaQueryVersion_dylibloader_wrapper_xinerama)(Display *, int *, int *);
+int (*XineramaIsActive_dylibloader_wrapper_xinerama)(Display *);
+XineramaScreenInfo *(*XineramaQueryScreens_dylibloader_wrapper_xinerama)(Display *, int *);
int initialize_xinerama(int verbose) {
void *handle;
char *error;
diff --git a/platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.h b/platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.h
index e3cedfc8ad..b421a0ecf5 100644
--- a/platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.h
+++ b/platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.h
@@ -2,13 +2,9 @@
#define DYLIBLOAD_WRAPPER_XINERAMA
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
-// generated by generate-wrapper.py 0.3 on 2023-01-23 15:11:35
-// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/extensions/Xinerama.h --sys-include "thirdparty/linuxbsd_headers/X11/extensions/Xinerama.h" --soname libXinerama.so.1 --init-name xinerama --output-header ./platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.c
+// generated by generate-wrapper.py 0.6 on 2024-11-09 02:52:36
+// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/extensions/Xinerama.h --sys-include thirdparty/linuxbsd_headers/X11/extensions/Xinerama.h --soname libXinerama.so.1 --init-name xinerama --output-header ./platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xinerama-so_wrap.c --ignore-other
//
-// NOTE: Generated from Xinerama 1.1.4.
-// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existent symbols inherited from
-// libX11, but absent in libXinerama.so.1, were removed.
#include <stdint.h>
#define XineramaQueryExtension XineramaQueryExtension_dylibloader_orig_xinerama
@@ -27,10 +23,10 @@ extern "C" {
#define XineramaQueryVersion XineramaQueryVersion_dylibloader_wrapper_xinerama
#define XineramaIsActive XineramaIsActive_dylibloader_wrapper_xinerama
#define XineramaQueryScreens XineramaQueryScreens_dylibloader_wrapper_xinerama
-extern int (*XineramaQueryExtension_dylibloader_wrapper_xinerama)( Display*, int*, int*);
-extern int (*XineramaQueryVersion_dylibloader_wrapper_xinerama)( Display*, int*, int*);
-extern int (*XineramaIsActive_dylibloader_wrapper_xinerama)( Display*);
-extern XineramaScreenInfo* (*XineramaQueryScreens_dylibloader_wrapper_xinerama)( Display*, int*);
+extern int (*XineramaQueryExtension_dylibloader_wrapper_xinerama)(Display *, int *, int *);
+extern int (*XineramaQueryVersion_dylibloader_wrapper_xinerama)(Display *, int *, int *);
+extern int (*XineramaIsActive_dylibloader_wrapper_xinerama)(Display *);
+extern XineramaScreenInfo *(*XineramaQueryScreens_dylibloader_wrapper_xinerama)(Display *, int *);
int initialize_xinerama(int verbose);
#ifdef __cplusplus
}
diff --git a/platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.c b/platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.c
index fc08b97e3c..8f031acb20 100644
--- a/platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.c
+++ b/platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.c
@@ -1,12 +1,8 @@
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
-// generated by generate-wrapper.py 0.3 on 2023-01-23 15:12:16
-// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/extensions/XInput2.h --sys-include "thirdparty/linuxbsd_headers/X11/extensions/XInput2.h" --soname libXi.so.6 --init-name xinput2 --output-header ./platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.c
+// generated by generate-wrapper.py 0.6 on 2024-11-09 02:52:36
+// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/extensions/XInput2.h --sys-include thirdparty/linuxbsd_headers/X11/extensions/XInput2.h --soname libXi.so.6 --init-name xinput2 --output-header ./platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.c --ignore-other
//
-// NOTE: Generated from Xi 1.7.10.
-// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existent symbols inherited from
-// libX11, liXext and libXfixes, but absent in libXi.so.6, were removed.
#include <stdint.h>
#define XIQueryPointer XIQueryPointer_dylibloader_orig_xinput2
@@ -80,40 +76,40 @@
#undef XIFreeDeviceInfo
#include <dlfcn.h>
#include <stdio.h>
-int (*XIQueryPointer_dylibloader_wrapper_xinput2)( Display*, int, Window, Window*, Window*, double*, double*, double*, double*, XIButtonState*, XIModifierState*, XIGroupState*);
-int (*XIWarpPointer_dylibloader_wrapper_xinput2)( Display*, int, Window, Window, double, double, unsigned int, unsigned int, double, double);
-int (*XIDefineCursor_dylibloader_wrapper_xinput2)( Display*, int, Window, Cursor);
-int (*XIUndefineCursor_dylibloader_wrapper_xinput2)( Display*, int, Window);
-int (*XIChangeHierarchy_dylibloader_wrapper_xinput2)( Display*, XIAnyHierarchyChangeInfo*, int);
-int (*XISetClientPointer_dylibloader_wrapper_xinput2)( Display*, Window, int);
-int (*XIGetClientPointer_dylibloader_wrapper_xinput2)( Display*, Window, int*);
-int (*XISelectEvents_dylibloader_wrapper_xinput2)( Display*, Window, XIEventMask*, int);
-XIEventMask* (*XIGetSelectedEvents_dylibloader_wrapper_xinput2)( Display*, Window, int*);
-int (*XIQueryVersion_dylibloader_wrapper_xinput2)( Display*, int*, int*);
-XIDeviceInfo* (*XIQueryDevice_dylibloader_wrapper_xinput2)( Display*, int, int*);
-int (*XISetFocus_dylibloader_wrapper_xinput2)( Display*, int, Window, Time);
-int (*XIGetFocus_dylibloader_wrapper_xinput2)( Display*, int, Window*);
-int (*XIGrabDevice_dylibloader_wrapper_xinput2)( Display*, int, Window, Time, Cursor, int, int, int, XIEventMask*);
-int (*XIUngrabDevice_dylibloader_wrapper_xinput2)( Display*, int, Time);
-int (*XIAllowEvents_dylibloader_wrapper_xinput2)( Display*, int, int, Time);
-int (*XIAllowTouchEvents_dylibloader_wrapper_xinput2)( Display*, int, unsigned int, Window, int);
-int (*XIGrabButton_dylibloader_wrapper_xinput2)( Display*, int, int, Window, Cursor, int, int, int, XIEventMask*, int, XIGrabModifiers*);
-int (*XIGrabKeycode_dylibloader_wrapper_xinput2)( Display*, int, int, Window, int, int, int, XIEventMask*, int, XIGrabModifiers*);
-int (*XIGrabEnter_dylibloader_wrapper_xinput2)( Display*, int, Window, Cursor, int, int, int, XIEventMask*, int, XIGrabModifiers*);
-int (*XIGrabFocusIn_dylibloader_wrapper_xinput2)( Display*, int, Window, int, int, int, XIEventMask*, int, XIGrabModifiers*);
-int (*XIGrabTouchBegin_dylibloader_wrapper_xinput2)( Display*, int, Window, int, XIEventMask*, int, XIGrabModifiers*);
-int (*XIUngrabButton_dylibloader_wrapper_xinput2)( Display*, int, int, Window, int, XIGrabModifiers*);
-int (*XIUngrabKeycode_dylibloader_wrapper_xinput2)( Display*, int, int, Window, int, XIGrabModifiers*);
-int (*XIUngrabEnter_dylibloader_wrapper_xinput2)( Display*, int, Window, int, XIGrabModifiers*);
-int (*XIUngrabFocusIn_dylibloader_wrapper_xinput2)( Display*, int, Window, int, XIGrabModifiers*);
-int (*XIUngrabTouchBegin_dylibloader_wrapper_xinput2)( Display*, int, Window, int, XIGrabModifiers*);
-Atom* (*XIListProperties_dylibloader_wrapper_xinput2)( Display*, int, int*);
-void (*XIChangeProperty_dylibloader_wrapper_xinput2)( Display*, int, Atom, Atom, int, int, unsigned char*, int);
-void (*XIDeleteProperty_dylibloader_wrapper_xinput2)( Display*, int, Atom);
-int (*XIGetProperty_dylibloader_wrapper_xinput2)( Display*, int, Atom, long, long, int, Atom, Atom*, int*, unsigned long*, unsigned long*, unsigned char**);
-void (*XIBarrierReleasePointers_dylibloader_wrapper_xinput2)( Display*, XIBarrierReleasePointerInfo*, int);
-void (*XIBarrierReleasePointer_dylibloader_wrapper_xinput2)( Display*, int, PointerBarrier, BarrierEventID);
-void (*XIFreeDeviceInfo_dylibloader_wrapper_xinput2)( XIDeviceInfo*);
+int (*XIQueryPointer_dylibloader_wrapper_xinput2)(Display *, int, Window, Window *, Window *, double *, double *, double *, double *, XIButtonState *, XIModifierState *, XIGroupState *);
+int (*XIWarpPointer_dylibloader_wrapper_xinput2)(Display *, int, Window, Window, double, double, unsigned int, unsigned int, double, double);
+int (*XIDefineCursor_dylibloader_wrapper_xinput2)(Display *, int, Window, Cursor);
+int (*XIUndefineCursor_dylibloader_wrapper_xinput2)(Display *, int, Window);
+int (*XIChangeHierarchy_dylibloader_wrapper_xinput2)(Display *, XIAnyHierarchyChangeInfo *, int);
+int (*XISetClientPointer_dylibloader_wrapper_xinput2)(Display *, Window, int);
+int (*XIGetClientPointer_dylibloader_wrapper_xinput2)(Display *, Window, int *);
+int (*XISelectEvents_dylibloader_wrapper_xinput2)(Display *, Window, XIEventMask *, int);
+XIEventMask *(*XIGetSelectedEvents_dylibloader_wrapper_xinput2)(Display *, Window, int *);
+int (*XIQueryVersion_dylibloader_wrapper_xinput2)(Display *, int *, int *);
+XIDeviceInfo *(*XIQueryDevice_dylibloader_wrapper_xinput2)(Display *, int, int *);
+int (*XISetFocus_dylibloader_wrapper_xinput2)(Display *, int, Window, Time);
+int (*XIGetFocus_dylibloader_wrapper_xinput2)(Display *, int, Window *);
+int (*XIGrabDevice_dylibloader_wrapper_xinput2)(Display *, int, Window, Time, Cursor, int, int, int, XIEventMask *);
+int (*XIUngrabDevice_dylibloader_wrapper_xinput2)(Display *, int, Time);
+int (*XIAllowEvents_dylibloader_wrapper_xinput2)(Display *, int, int, Time);
+int (*XIAllowTouchEvents_dylibloader_wrapper_xinput2)(Display *, int, unsigned int, Window, int);
+int (*XIGrabButton_dylibloader_wrapper_xinput2)(Display *, int, int, Window, Cursor, int, int, int, XIEventMask *, int, XIGrabModifiers *);
+int (*XIGrabKeycode_dylibloader_wrapper_xinput2)(Display *, int, int, Window, int, int, int, XIEventMask *, int, XIGrabModifiers *);
+int (*XIGrabEnter_dylibloader_wrapper_xinput2)(Display *, int, Window, Cursor, int, int, int, XIEventMask *, int, XIGrabModifiers *);
+int (*XIGrabFocusIn_dylibloader_wrapper_xinput2)(Display *, int, Window, int, int, int, XIEventMask *, int, XIGrabModifiers *);
+int (*XIGrabTouchBegin_dylibloader_wrapper_xinput2)(Display *, int, Window, int, XIEventMask *, int, XIGrabModifiers *);
+int (*XIUngrabButton_dylibloader_wrapper_xinput2)(Display *, int, int, Window, int, XIGrabModifiers *);
+int (*XIUngrabKeycode_dylibloader_wrapper_xinput2)(Display *, int, int, Window, int, XIGrabModifiers *);
+int (*XIUngrabEnter_dylibloader_wrapper_xinput2)(Display *, int, Window, int, XIGrabModifiers *);
+int (*XIUngrabFocusIn_dylibloader_wrapper_xinput2)(Display *, int, Window, int, XIGrabModifiers *);
+int (*XIUngrabTouchBegin_dylibloader_wrapper_xinput2)(Display *, int, Window, int, XIGrabModifiers *);
+Atom *(*XIListProperties_dylibloader_wrapper_xinput2)(Display *, int, int *);
+void (*XIChangeProperty_dylibloader_wrapper_xinput2)(Display *, int, Atom, Atom, int, int, unsigned char *, int);
+void (*XIDeleteProperty_dylibloader_wrapper_xinput2)(Display *, int, Atom);
+int (*XIGetProperty_dylibloader_wrapper_xinput2)(Display *, int, Atom, long, long, int, Atom, Atom *, int *, unsigned long *, unsigned long *, unsigned char **);
+void (*XIBarrierReleasePointers_dylibloader_wrapper_xinput2)(Display *, XIBarrierReleasePointerInfo *, int);
+void (*XIBarrierReleasePointer_dylibloader_wrapper_xinput2)(Display *, int, PointerBarrier, BarrierEventID);
+void (*XIFreeDeviceInfo_dylibloader_wrapper_xinput2)(XIDeviceInfo *);
int initialize_xinput2(int verbose) {
void *handle;
char *error;
diff --git a/platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.h b/platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.h
index 571072c3cd..7c54dc080a 100644
--- a/platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.h
+++ b/platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.h
@@ -2,13 +2,9 @@
#define DYLIBLOAD_WRAPPER_XINPUT2
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
-// generated by generate-wrapper.py 0.3 on 2023-01-23 15:12:16
-// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/extensions/XInput2.h --sys-include "thirdparty/linuxbsd_headers/X11/extensions/XInput2.h" --soname libXi.so.6 --init-name xinput2 --output-header ./platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.c
+// generated by generate-wrapper.py 0.6 on 2024-11-09 02:52:36
+// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/extensions/XInput2.h --sys-include thirdparty/linuxbsd_headers/X11/extensions/XInput2.h --soname libXi.so.6 --init-name xinput2 --output-header ./platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xinput2-so_wrap.c --ignore-other
//
-// NOTE: Generated from Xi 1.7.10.
-// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existent symbols inherited from
-// libX11, liXext and libXfixes, but absent in libXi.so.6, were removed.
#include <stdint.h>
#define XIQueryPointer XIQueryPointer_dylibloader_orig_xinput2
@@ -117,40 +113,40 @@ extern "C" {
#define XIBarrierReleasePointers XIBarrierReleasePointers_dylibloader_wrapper_xinput2
#define XIBarrierReleasePointer XIBarrierReleasePointer_dylibloader_wrapper_xinput2
#define XIFreeDeviceInfo XIFreeDeviceInfo_dylibloader_wrapper_xinput2
-extern int (*XIQueryPointer_dylibloader_wrapper_xinput2)( Display*, int, Window, Window*, Window*, double*, double*, double*, double*, XIButtonState*, XIModifierState*, XIGroupState*);
-extern int (*XIWarpPointer_dylibloader_wrapper_xinput2)( Display*, int, Window, Window, double, double, unsigned int, unsigned int, double, double);
-extern int (*XIDefineCursor_dylibloader_wrapper_xinput2)( Display*, int, Window, Cursor);
-extern int (*XIUndefineCursor_dylibloader_wrapper_xinput2)( Display*, int, Window);
-extern int (*XIChangeHierarchy_dylibloader_wrapper_xinput2)( Display*, XIAnyHierarchyChangeInfo*, int);
-extern int (*XISetClientPointer_dylibloader_wrapper_xinput2)( Display*, Window, int);
-extern int (*XIGetClientPointer_dylibloader_wrapper_xinput2)( Display*, Window, int*);
-extern int (*XISelectEvents_dylibloader_wrapper_xinput2)( Display*, Window, XIEventMask*, int);
-extern XIEventMask* (*XIGetSelectedEvents_dylibloader_wrapper_xinput2)( Display*, Window, int*);
-extern int (*XIQueryVersion_dylibloader_wrapper_xinput2)( Display*, int*, int*);
-extern XIDeviceInfo* (*XIQueryDevice_dylibloader_wrapper_xinput2)( Display*, int, int*);
-extern int (*XISetFocus_dylibloader_wrapper_xinput2)( Display*, int, Window, Time);
-extern int (*XIGetFocus_dylibloader_wrapper_xinput2)( Display*, int, Window*);
-extern int (*XIGrabDevice_dylibloader_wrapper_xinput2)( Display*, int, Window, Time, Cursor, int, int, int, XIEventMask*);
-extern int (*XIUngrabDevice_dylibloader_wrapper_xinput2)( Display*, int, Time);
-extern int (*XIAllowEvents_dylibloader_wrapper_xinput2)( Display*, int, int, Time);
-extern int (*XIAllowTouchEvents_dylibloader_wrapper_xinput2)( Display*, int, unsigned int, Window, int);
-extern int (*XIGrabButton_dylibloader_wrapper_xinput2)( Display*, int, int, Window, Cursor, int, int, int, XIEventMask*, int, XIGrabModifiers*);
-extern int (*XIGrabKeycode_dylibloader_wrapper_xinput2)( Display*, int, int, Window, int, int, int, XIEventMask*, int, XIGrabModifiers*);
-extern int (*XIGrabEnter_dylibloader_wrapper_xinput2)( Display*, int, Window, Cursor, int, int, int, XIEventMask*, int, XIGrabModifiers*);
-extern int (*XIGrabFocusIn_dylibloader_wrapper_xinput2)( Display*, int, Window, int, int, int, XIEventMask*, int, XIGrabModifiers*);
-extern int (*XIGrabTouchBegin_dylibloader_wrapper_xinput2)( Display*, int, Window, int, XIEventMask*, int, XIGrabModifiers*);
-extern int (*XIUngrabButton_dylibloader_wrapper_xinput2)( Display*, int, int, Window, int, XIGrabModifiers*);
-extern int (*XIUngrabKeycode_dylibloader_wrapper_xinput2)( Display*, int, int, Window, int, XIGrabModifiers*);
-extern int (*XIUngrabEnter_dylibloader_wrapper_xinput2)( Display*, int, Window, int, XIGrabModifiers*);
-extern int (*XIUngrabFocusIn_dylibloader_wrapper_xinput2)( Display*, int, Window, int, XIGrabModifiers*);
-extern int (*XIUngrabTouchBegin_dylibloader_wrapper_xinput2)( Display*, int, Window, int, XIGrabModifiers*);
-extern Atom* (*XIListProperties_dylibloader_wrapper_xinput2)( Display*, int, int*);
-extern void (*XIChangeProperty_dylibloader_wrapper_xinput2)( Display*, int, Atom, Atom, int, int, unsigned char*, int);
-extern void (*XIDeleteProperty_dylibloader_wrapper_xinput2)( Display*, int, Atom);
-extern int (*XIGetProperty_dylibloader_wrapper_xinput2)( Display*, int, Atom, long, long, int, Atom, Atom*, int*, unsigned long*, unsigned long*, unsigned char**);
-extern void (*XIBarrierReleasePointers_dylibloader_wrapper_xinput2)( Display*, XIBarrierReleasePointerInfo*, int);
-extern void (*XIBarrierReleasePointer_dylibloader_wrapper_xinput2)( Display*, int, PointerBarrier, BarrierEventID);
-extern void (*XIFreeDeviceInfo_dylibloader_wrapper_xinput2)( XIDeviceInfo*);
+extern int (*XIQueryPointer_dylibloader_wrapper_xinput2)(Display *, int, Window, Window *, Window *, double *, double *, double *, double *, XIButtonState *, XIModifierState *, XIGroupState *);
+extern int (*XIWarpPointer_dylibloader_wrapper_xinput2)(Display *, int, Window, Window, double, double, unsigned int, unsigned int, double, double);
+extern int (*XIDefineCursor_dylibloader_wrapper_xinput2)(Display *, int, Window, Cursor);
+extern int (*XIUndefineCursor_dylibloader_wrapper_xinput2)(Display *, int, Window);
+extern int (*XIChangeHierarchy_dylibloader_wrapper_xinput2)(Display *, XIAnyHierarchyChangeInfo *, int);
+extern int (*XISetClientPointer_dylibloader_wrapper_xinput2)(Display *, Window, int);
+extern int (*XIGetClientPointer_dylibloader_wrapper_xinput2)(Display *, Window, int *);
+extern int (*XISelectEvents_dylibloader_wrapper_xinput2)(Display *, Window, XIEventMask *, int);
+extern XIEventMask *(*XIGetSelectedEvents_dylibloader_wrapper_xinput2)(Display *, Window, int *);
+extern int (*XIQueryVersion_dylibloader_wrapper_xinput2)(Display *, int *, int *);
+extern XIDeviceInfo *(*XIQueryDevice_dylibloader_wrapper_xinput2)(Display *, int, int *);
+extern int (*XISetFocus_dylibloader_wrapper_xinput2)(Display *, int, Window, Time);
+extern int (*XIGetFocus_dylibloader_wrapper_xinput2)(Display *, int, Window *);
+extern int (*XIGrabDevice_dylibloader_wrapper_xinput2)(Display *, int, Window, Time, Cursor, int, int, int, XIEventMask *);
+extern int (*XIUngrabDevice_dylibloader_wrapper_xinput2)(Display *, int, Time);
+extern int (*XIAllowEvents_dylibloader_wrapper_xinput2)(Display *, int, int, Time);
+extern int (*XIAllowTouchEvents_dylibloader_wrapper_xinput2)(Display *, int, unsigned int, Window, int);
+extern int (*XIGrabButton_dylibloader_wrapper_xinput2)(Display *, int, int, Window, Cursor, int, int, int, XIEventMask *, int, XIGrabModifiers *);
+extern int (*XIGrabKeycode_dylibloader_wrapper_xinput2)(Display *, int, int, Window, int, int, int, XIEventMask *, int, XIGrabModifiers *);
+extern int (*XIGrabEnter_dylibloader_wrapper_xinput2)(Display *, int, Window, Cursor, int, int, int, XIEventMask *, int, XIGrabModifiers *);
+extern int (*XIGrabFocusIn_dylibloader_wrapper_xinput2)(Display *, int, Window, int, int, int, XIEventMask *, int, XIGrabModifiers *);
+extern int (*XIGrabTouchBegin_dylibloader_wrapper_xinput2)(Display *, int, Window, int, XIEventMask *, int, XIGrabModifiers *);
+extern int (*XIUngrabButton_dylibloader_wrapper_xinput2)(Display *, int, int, Window, int, XIGrabModifiers *);
+extern int (*XIUngrabKeycode_dylibloader_wrapper_xinput2)(Display *, int, int, Window, int, XIGrabModifiers *);
+extern int (*XIUngrabEnter_dylibloader_wrapper_xinput2)(Display *, int, Window, int, XIGrabModifiers *);
+extern int (*XIUngrabFocusIn_dylibloader_wrapper_xinput2)(Display *, int, Window, int, XIGrabModifiers *);
+extern int (*XIUngrabTouchBegin_dylibloader_wrapper_xinput2)(Display *, int, Window, int, XIGrabModifiers *);
+extern Atom *(*XIListProperties_dylibloader_wrapper_xinput2)(Display *, int, int *);
+extern void (*XIChangeProperty_dylibloader_wrapper_xinput2)(Display *, int, Atom, Atom, int, int, unsigned char *, int);
+extern void (*XIDeleteProperty_dylibloader_wrapper_xinput2)(Display *, int, Atom);
+extern int (*XIGetProperty_dylibloader_wrapper_xinput2)(Display *, int, Atom, long, long, int, Atom, Atom *, int *, unsigned long *, unsigned long *, unsigned char **);
+extern void (*XIBarrierReleasePointers_dylibloader_wrapper_xinput2)(Display *, XIBarrierReleasePointerInfo *, int);
+extern void (*XIBarrierReleasePointer_dylibloader_wrapper_xinput2)(Display *, int, PointerBarrier, BarrierEventID);
+extern void (*XIFreeDeviceInfo_dylibloader_wrapper_xinput2)(XIDeviceInfo *);
int initialize_xinput2(int verbose);
#ifdef __cplusplus
}
diff --git a/platform/linuxbsd/x11/dynwrappers/xlib-so_wrap.c b/platform/linuxbsd/x11/dynwrappers/xlib-so_wrap.c
index d2838569b0..8500f20198 100644
--- a/platform/linuxbsd/x11/dynwrappers/xlib-so_wrap.c
+++ b/platform/linuxbsd/x11/dynwrappers/xlib-so_wrap.c
@@ -1,14 +1,8 @@
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
-// generated by generate-wrapper.py 0.3 on 2023-01-23 15:13:26
-// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/Xlib.h --include ./thirdparty/linuxbsd_headers/X11/Xutil.h --include ./thirdparty/linuxbsd_headers/X11/XKBlib.h --sys-include "thirdparty/linuxbsd_headers/X11/Xlib.h" --sys-include "thirdparty/linuxbsd_headers/X11/Xutil.h" --sys-include "thirdparty/linuxbsd_headers/X11/XKBlib.h" --soname libX11.so.6 --init-name xlib --omit-prefix XkbGetDeviceIndicatorState --omit-prefix XkbAddSymInterpret --output-header ./platform/linuxbsd/x11/dynwrappers/xlib-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xlib-so_wrap.c~
+// generated by generate-wrapper.py 0.6 on 2024-11-09 02:52:36
+// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/Xlib.h --include ./thirdparty/linuxbsd_headers/X11/Xutil.h --include ./thirdparty/linuxbsd_headers/X11/XKBlib.h --sys-include thirdparty/linuxbsd_headers/X11/Xlib.h --sys-include thirdparty/linuxbsd_headers/X11/Xutil.h --sys-include thirdparty/linuxbsd_headers/X11/XKBlib.h --soname libX11.so.6 --init-name xlib --omit-prefix XkbGetDeviceIndicatorState --omit-prefix XkbAddSymInterpret --output-header ./platform/linuxbsd/x11/dynwrappers/xlib-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xlib-so_wrap.c
//
-// NOTE: Generated from Xlib 1.6.9.
-// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, the type of the third argument of
-// XIfEvent, XPeekIfEvent and XCheckIfEvent had to be fixed as it wasn't parsed
-// fully (it's a Bool function pointer, but it was just being parsed as an int
-// pointer).
#include <stdint.h>
#define _Xmblen _Xmblen_dylibloader_orig_xlib
@@ -100,6 +94,7 @@
#define XScreenNumberOfScreen XScreenNumberOfScreen_dylibloader_orig_xlib
#define XSetErrorHandler XSetErrorHandler_dylibloader_orig_xlib
#define XSetIOErrorHandler XSetIOErrorHandler_dylibloader_orig_xlib
+#define XSetIOErrorExitHandler XSetIOErrorExitHandler_dylibloader_orig_xlib
#define XListPixmapFormats XListPixmapFormats_dylibloader_orig_xlib
#define XListDepths XListDepths_dylibloader_orig_xlib
#define XReconfigureWMWindow XReconfigureWMWindow_dylibloader_orig_xlib
@@ -423,6 +418,7 @@
#define _Xwctomb _Xwctomb_dylibloader_orig_xlib
#define XGetEventData XGetEventData_dylibloader_orig_xlib
#define XFreeEventData XFreeEventData_dylibloader_orig_xlib
+#define XFreeThreads XFreeThreads_dylibloader_orig_xlib
#define XAllocClassHint XAllocClassHint_dylibloader_orig_xlib
#define XAllocIconSize XAllocIconSize_dylibloader_orig_xlib
#define XAllocSizeHints XAllocSizeHints_dylibloader_orig_xlib
@@ -706,6 +702,7 @@
#undef XScreenNumberOfScreen
#undef XSetErrorHandler
#undef XSetIOErrorHandler
+#undef XSetIOErrorExitHandler
#undef XListPixmapFormats
#undef XListDepths
#undef XReconfigureWMWindow
@@ -1029,6 +1026,7 @@
#undef _Xwctomb
#undef XGetEventData
#undef XFreeEventData
+#undef XFreeThreads
#undef XAllocClassHint
#undef XAllocIconSize
#undef XAllocSizeHints
@@ -1222,609 +1220,611 @@
#undef XkbUpdateKeyTypeVirtualMods
#include <dlfcn.h>
#include <stdio.h>
-int (*_Xmblen_dylibloader_wrapper_xlib)( char*, int);
-XFontStruct* (*XLoadQueryFont_dylibloader_wrapper_xlib)( Display*,const char*);
-XFontStruct* (*XQueryFont_dylibloader_wrapper_xlib)( Display*, XID);
-XTimeCoord* (*XGetMotionEvents_dylibloader_wrapper_xlib)( Display*, Window, Time, Time, int*);
-XModifierKeymap* (*XDeleteModifiermapEntry_dylibloader_wrapper_xlib)( XModifierKeymap*, KeyCode, int);
-XModifierKeymap* (*XGetModifierMapping_dylibloader_wrapper_xlib)( Display*);
-XModifierKeymap* (*XInsertModifiermapEntry_dylibloader_wrapper_xlib)( XModifierKeymap*, KeyCode, int);
-XModifierKeymap* (*XNewModifiermap_dylibloader_wrapper_xlib)( int);
-XImage* (*XCreateImage_dylibloader_wrapper_xlib)( Display*, Visual*, unsigned int, int, int, char*, unsigned int, unsigned int, int, int);
-int (*XInitImage_dylibloader_wrapper_xlib)( XImage*);
-XImage* (*XGetImage_dylibloader_wrapper_xlib)( Display*, Drawable, int, int, unsigned int, unsigned int, unsigned long, int);
-XImage* (*XGetSubImage_dylibloader_wrapper_xlib)( Display*, Drawable, int, int, unsigned int, unsigned int, unsigned long, int, XImage*, int, int);
-Display* (*XOpenDisplay_dylibloader_wrapper_xlib)(const char*);
-void (*XrmInitialize_dylibloader_wrapper_xlib)( void);
-char* (*XFetchBytes_dylibloader_wrapper_xlib)( Display*, int*);
-char* (*XFetchBuffer_dylibloader_wrapper_xlib)( Display*, int*, int);
-char* (*XGetAtomName_dylibloader_wrapper_xlib)( Display*, Atom);
-int (*XGetAtomNames_dylibloader_wrapper_xlib)( Display*, Atom*, int, char**);
-char* (*XGetDefault_dylibloader_wrapper_xlib)( Display*,const char*,const char*);
-char* (*XDisplayName_dylibloader_wrapper_xlib)(const char*);
-char* (*XKeysymToString_dylibloader_wrapper_xlib)( KeySym);
-int* (*XSynchronize_dylibloader_wrapper_xlib)( Display*, int);
-int* (*XSetAfterFunction_dylibloader_wrapper_xlib)( Display*, int*);
-Atom (*XInternAtom_dylibloader_wrapper_xlib)( Display*,const char*, int);
-int (*XInternAtoms_dylibloader_wrapper_xlib)( Display*, char**, int, int, Atom*);
-Colormap (*XCopyColormapAndFree_dylibloader_wrapper_xlib)( Display*, Colormap);
-Colormap (*XCreateColormap_dylibloader_wrapper_xlib)( Display*, Window, Visual*, int);
-Cursor (*XCreatePixmapCursor_dylibloader_wrapper_xlib)( Display*, Pixmap, Pixmap, XColor*, XColor*, unsigned int, unsigned int);
-Cursor (*XCreateGlyphCursor_dylibloader_wrapper_xlib)( Display*, Font, Font, unsigned int, unsigned int,const XColor*,const XColor*);
-Cursor (*XCreateFontCursor_dylibloader_wrapper_xlib)( Display*, unsigned int);
-Font (*XLoadFont_dylibloader_wrapper_xlib)( Display*,const char*);
-GC (*XCreateGC_dylibloader_wrapper_xlib)( Display*, Drawable, unsigned long, XGCValues*);
-GContext (*XGContextFromGC_dylibloader_wrapper_xlib)( GC);
-void (*XFlushGC_dylibloader_wrapper_xlib)( Display*, GC);
-Pixmap (*XCreatePixmap_dylibloader_wrapper_xlib)( Display*, Drawable, unsigned int, unsigned int, unsigned int);
-Pixmap (*XCreateBitmapFromData_dylibloader_wrapper_xlib)( Display*, Drawable,const char*, unsigned int, unsigned int);
-Pixmap (*XCreatePixmapFromBitmapData_dylibloader_wrapper_xlib)( Display*, Drawable, char*, unsigned int, unsigned int, unsigned long, unsigned long, unsigned int);
-Window (*XCreateSimpleWindow_dylibloader_wrapper_xlib)( Display*, Window, int, int, unsigned int, unsigned int, unsigned int, unsigned long, unsigned long);
-Window (*XGetSelectionOwner_dylibloader_wrapper_xlib)( Display*, Atom);
-Window (*XCreateWindow_dylibloader_wrapper_xlib)( Display*, Window, int, int, unsigned int, unsigned int, unsigned int, int, unsigned int, Visual*, unsigned long, XSetWindowAttributes*);
-Colormap* (*XListInstalledColormaps_dylibloader_wrapper_xlib)( Display*, Window, int*);
-char** (*XListFonts_dylibloader_wrapper_xlib)( Display*,const char*, int, int*);
-char** (*XListFontsWithInfo_dylibloader_wrapper_xlib)( Display*,const char*, int, int*, XFontStruct**);
-char** (*XGetFontPath_dylibloader_wrapper_xlib)( Display*, int*);
-char** (*XListExtensions_dylibloader_wrapper_xlib)( Display*, int*);
-Atom* (*XListProperties_dylibloader_wrapper_xlib)( Display*, Window, int*);
-XHostAddress* (*XListHosts_dylibloader_wrapper_xlib)( Display*, int*, int*);
-KeySym (*XKeycodeToKeysym_dylibloader_wrapper_xlib)( Display*, KeyCode, int);
-KeySym (*XLookupKeysym_dylibloader_wrapper_xlib)( XKeyEvent*, int);
-KeySym* (*XGetKeyboardMapping_dylibloader_wrapper_xlib)( Display*, KeyCode, int, int*);
-KeySym (*XStringToKeysym_dylibloader_wrapper_xlib)(const char*);
-long (*XMaxRequestSize_dylibloader_wrapper_xlib)( Display*);
-long (*XExtendedMaxRequestSize_dylibloader_wrapper_xlib)( Display*);
-char* (*XResourceManagerString_dylibloader_wrapper_xlib)( Display*);
-char* (*XScreenResourceString_dylibloader_wrapper_xlib)( Screen*);
-unsigned long (*XDisplayMotionBufferSize_dylibloader_wrapper_xlib)( Display*);
-VisualID (*XVisualIDFromVisual_dylibloader_wrapper_xlib)( Visual*);
-int (*XInitThreads_dylibloader_wrapper_xlib)( void);
-void (*XLockDisplay_dylibloader_wrapper_xlib)( Display*);
-void (*XUnlockDisplay_dylibloader_wrapper_xlib)( Display*);
-XExtCodes* (*XInitExtension_dylibloader_wrapper_xlib)( Display*,const char*);
-XExtCodes* (*XAddExtension_dylibloader_wrapper_xlib)( Display*);
-XExtData* (*XFindOnExtensionList_dylibloader_wrapper_xlib)( XExtData**, int);
-XExtData** (*XEHeadOfExtensionList_dylibloader_wrapper_xlib)( XEDataObject);
-Window (*XRootWindow_dylibloader_wrapper_xlib)( Display*, int);
-Window (*XDefaultRootWindow_dylibloader_wrapper_xlib)( Display*);
-Window (*XRootWindowOfScreen_dylibloader_wrapper_xlib)( Screen*);
-Visual* (*XDefaultVisual_dylibloader_wrapper_xlib)( Display*, int);
-Visual* (*XDefaultVisualOfScreen_dylibloader_wrapper_xlib)( Screen*);
-GC (*XDefaultGC_dylibloader_wrapper_xlib)( Display*, int);
-GC (*XDefaultGCOfScreen_dylibloader_wrapper_xlib)( Screen*);
-unsigned long (*XBlackPixel_dylibloader_wrapper_xlib)( Display*, int);
-unsigned long (*XWhitePixel_dylibloader_wrapper_xlib)( Display*, int);
-unsigned long (*XAllPlanes_dylibloader_wrapper_xlib)( void);
-unsigned long (*XBlackPixelOfScreen_dylibloader_wrapper_xlib)( Screen*);
-unsigned long (*XWhitePixelOfScreen_dylibloader_wrapper_xlib)( Screen*);
-unsigned long (*XNextRequest_dylibloader_wrapper_xlib)( Display*);
-unsigned long (*XLastKnownRequestProcessed_dylibloader_wrapper_xlib)( Display*);
-char* (*XServerVendor_dylibloader_wrapper_xlib)( Display*);
-char* (*XDisplayString_dylibloader_wrapper_xlib)( Display*);
-Colormap (*XDefaultColormap_dylibloader_wrapper_xlib)( Display*, int);
-Colormap (*XDefaultColormapOfScreen_dylibloader_wrapper_xlib)( Screen*);
-Display* (*XDisplayOfScreen_dylibloader_wrapper_xlib)( Screen*);
-Screen* (*XScreenOfDisplay_dylibloader_wrapper_xlib)( Display*, int);
-Screen* (*XDefaultScreenOfDisplay_dylibloader_wrapper_xlib)( Display*);
-long (*XEventMaskOfScreen_dylibloader_wrapper_xlib)( Screen*);
-int (*XScreenNumberOfScreen_dylibloader_wrapper_xlib)( Screen*);
-XErrorHandler (*XSetErrorHandler_dylibloader_wrapper_xlib)( XErrorHandler);
-XIOErrorHandler (*XSetIOErrorHandler_dylibloader_wrapper_xlib)( XIOErrorHandler);
-XPixmapFormatValues* (*XListPixmapFormats_dylibloader_wrapper_xlib)( Display*, int*);
-int* (*XListDepths_dylibloader_wrapper_xlib)( Display*, int, int*);
-int (*XReconfigureWMWindow_dylibloader_wrapper_xlib)( Display*, Window, int, unsigned int, XWindowChanges*);
-int (*XGetWMProtocols_dylibloader_wrapper_xlib)( Display*, Window, Atom**, int*);
-int (*XSetWMProtocols_dylibloader_wrapper_xlib)( Display*, Window, Atom*, int);
-int (*XIconifyWindow_dylibloader_wrapper_xlib)( Display*, Window, int);
-int (*XWithdrawWindow_dylibloader_wrapper_xlib)( Display*, Window, int);
-int (*XGetCommand_dylibloader_wrapper_xlib)( Display*, Window, char***, int*);
-int (*XGetWMColormapWindows_dylibloader_wrapper_xlib)( Display*, Window, Window**, int*);
-int (*XSetWMColormapWindows_dylibloader_wrapper_xlib)( Display*, Window, Window*, int);
-void (*XFreeStringList_dylibloader_wrapper_xlib)( char**);
-int (*XSetTransientForHint_dylibloader_wrapper_xlib)( Display*, Window, Window);
-int (*XActivateScreenSaver_dylibloader_wrapper_xlib)( Display*);
-int (*XAddHost_dylibloader_wrapper_xlib)( Display*, XHostAddress*);
-int (*XAddHosts_dylibloader_wrapper_xlib)( Display*, XHostAddress*, int);
-int (*XAddToExtensionList_dylibloader_wrapper_xlib)(struct _XExtData**, XExtData*);
-int (*XAddToSaveSet_dylibloader_wrapper_xlib)( Display*, Window);
-int (*XAllocColor_dylibloader_wrapper_xlib)( Display*, Colormap, XColor*);
-int (*XAllocColorCells_dylibloader_wrapper_xlib)( Display*, Colormap, int, unsigned long*, unsigned int, unsigned long*, unsigned int);
-int (*XAllocColorPlanes_dylibloader_wrapper_xlib)( Display*, Colormap, int, unsigned long*, int, int, int, int, unsigned long*, unsigned long*, unsigned long*);
-int (*XAllocNamedColor_dylibloader_wrapper_xlib)( Display*, Colormap,const char*, XColor*, XColor*);
-int (*XAllowEvents_dylibloader_wrapper_xlib)( Display*, int, Time);
-int (*XAutoRepeatOff_dylibloader_wrapper_xlib)( Display*);
-int (*XAutoRepeatOn_dylibloader_wrapper_xlib)( Display*);
-int (*XBell_dylibloader_wrapper_xlib)( Display*, int);
-int (*XBitmapBitOrder_dylibloader_wrapper_xlib)( Display*);
-int (*XBitmapPad_dylibloader_wrapper_xlib)( Display*);
-int (*XBitmapUnit_dylibloader_wrapper_xlib)( Display*);
-int (*XCellsOfScreen_dylibloader_wrapper_xlib)( Screen*);
-int (*XChangeActivePointerGrab_dylibloader_wrapper_xlib)( Display*, unsigned int, Cursor, Time);
-int (*XChangeGC_dylibloader_wrapper_xlib)( Display*, GC, unsigned long, XGCValues*);
-int (*XChangeKeyboardControl_dylibloader_wrapper_xlib)( Display*, unsigned long, XKeyboardControl*);
-int (*XChangeKeyboardMapping_dylibloader_wrapper_xlib)( Display*, int, int, KeySym*, int);
-int (*XChangePointerControl_dylibloader_wrapper_xlib)( Display*, int, int, int, int, int);
-int (*XChangeProperty_dylibloader_wrapper_xlib)( Display*, Window, Atom, Atom, int, int,const unsigned char*, int);
-int (*XChangeSaveSet_dylibloader_wrapper_xlib)( Display*, Window, int);
-int (*XChangeWindowAttributes_dylibloader_wrapper_xlib)( Display*, Window, unsigned long, XSetWindowAttributes*);
-int (*XCheckIfEvent_dylibloader_wrapper_xlib)( Display*, XEvent*, Bool (*) (Display*, XEvent*, XPointer), XPointer);
-int (*XCheckMaskEvent_dylibloader_wrapper_xlib)( Display*, long, XEvent*);
-int (*XCheckTypedEvent_dylibloader_wrapper_xlib)( Display*, int, XEvent*);
-int (*XCheckTypedWindowEvent_dylibloader_wrapper_xlib)( Display*, Window, int, XEvent*);
-int (*XCheckWindowEvent_dylibloader_wrapper_xlib)( Display*, Window, long, XEvent*);
-int (*XCirculateSubwindows_dylibloader_wrapper_xlib)( Display*, Window, int);
-int (*XCirculateSubwindowsDown_dylibloader_wrapper_xlib)( Display*, Window);
-int (*XCirculateSubwindowsUp_dylibloader_wrapper_xlib)( Display*, Window);
-int (*XClearArea_dylibloader_wrapper_xlib)( Display*, Window, int, int, unsigned int, unsigned int, int);
-int (*XClearWindow_dylibloader_wrapper_xlib)( Display*, Window);
-int (*XCloseDisplay_dylibloader_wrapper_xlib)( Display*);
-int (*XConfigureWindow_dylibloader_wrapper_xlib)( Display*, Window, unsigned int, XWindowChanges*);
-int (*XConnectionNumber_dylibloader_wrapper_xlib)( Display*);
-int (*XConvertSelection_dylibloader_wrapper_xlib)( Display*, Atom, Atom, Atom, Window, Time);
-int (*XCopyArea_dylibloader_wrapper_xlib)( Display*, Drawable, Drawable, GC, int, int, unsigned int, unsigned int, int, int);
-int (*XCopyGC_dylibloader_wrapper_xlib)( Display*, GC, unsigned long, GC);
-int (*XCopyPlane_dylibloader_wrapper_xlib)( Display*, Drawable, Drawable, GC, int, int, unsigned int, unsigned int, int, int, unsigned long);
-int (*XDefaultDepth_dylibloader_wrapper_xlib)( Display*, int);
-int (*XDefaultDepthOfScreen_dylibloader_wrapper_xlib)( Screen*);
-int (*XDefaultScreen_dylibloader_wrapper_xlib)( Display*);
-int (*XDefineCursor_dylibloader_wrapper_xlib)( Display*, Window, Cursor);
-int (*XDeleteProperty_dylibloader_wrapper_xlib)( Display*, Window, Atom);
-int (*XDestroyWindow_dylibloader_wrapper_xlib)( Display*, Window);
-int (*XDestroySubwindows_dylibloader_wrapper_xlib)( Display*, Window);
-int (*XDoesBackingStore_dylibloader_wrapper_xlib)( Screen*);
-int (*XDoesSaveUnders_dylibloader_wrapper_xlib)( Screen*);
-int (*XDisableAccessControl_dylibloader_wrapper_xlib)( Display*);
-int (*XDisplayCells_dylibloader_wrapper_xlib)( Display*, int);
-int (*XDisplayHeight_dylibloader_wrapper_xlib)( Display*, int);
-int (*XDisplayHeightMM_dylibloader_wrapper_xlib)( Display*, int);
-int (*XDisplayKeycodes_dylibloader_wrapper_xlib)( Display*, int*, int*);
-int (*XDisplayPlanes_dylibloader_wrapper_xlib)( Display*, int);
-int (*XDisplayWidth_dylibloader_wrapper_xlib)( Display*, int);
-int (*XDisplayWidthMM_dylibloader_wrapper_xlib)( Display*, int);
-int (*XDrawArc_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, unsigned int, unsigned int, int, int);
-int (*XDrawArcs_dylibloader_wrapper_xlib)( Display*, Drawable, GC, XArc*, int);
-int (*XDrawImageString_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int,const char*, int);
-int (*XDrawImageString16_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int,const XChar2b*, int);
-int (*XDrawLine_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, int, int);
-int (*XDrawLines_dylibloader_wrapper_xlib)( Display*, Drawable, GC, XPoint*, int, int);
-int (*XDrawPoint_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int);
-int (*XDrawPoints_dylibloader_wrapper_xlib)( Display*, Drawable, GC, XPoint*, int, int);
-int (*XDrawRectangle_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, unsigned int, unsigned int);
-int (*XDrawRectangles_dylibloader_wrapper_xlib)( Display*, Drawable, GC, XRectangle*, int);
-int (*XDrawSegments_dylibloader_wrapper_xlib)( Display*, Drawable, GC, XSegment*, int);
-int (*XDrawString_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int,const char*, int);
-int (*XDrawString16_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int,const XChar2b*, int);
-int (*XDrawText_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, XTextItem*, int);
-int (*XDrawText16_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, XTextItem16*, int);
-int (*XEnableAccessControl_dylibloader_wrapper_xlib)( Display*);
-int (*XEventsQueued_dylibloader_wrapper_xlib)( Display*, int);
-int (*XFetchName_dylibloader_wrapper_xlib)( Display*, Window, char**);
-int (*XFillArc_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, unsigned int, unsigned int, int, int);
-int (*XFillArcs_dylibloader_wrapper_xlib)( Display*, Drawable, GC, XArc*, int);
-int (*XFillPolygon_dylibloader_wrapper_xlib)( Display*, Drawable, GC, XPoint*, int, int, int);
-int (*XFillRectangle_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, unsigned int, unsigned int);
-int (*XFillRectangles_dylibloader_wrapper_xlib)( Display*, Drawable, GC, XRectangle*, int);
-int (*XFlush_dylibloader_wrapper_xlib)( Display*);
-int (*XForceScreenSaver_dylibloader_wrapper_xlib)( Display*, int);
-int (*XFree_dylibloader_wrapper_xlib)( void*);
-int (*XFreeColormap_dylibloader_wrapper_xlib)( Display*, Colormap);
-int (*XFreeColors_dylibloader_wrapper_xlib)( Display*, Colormap, unsigned long*, int, unsigned long);
-int (*XFreeCursor_dylibloader_wrapper_xlib)( Display*, Cursor);
-int (*XFreeExtensionList_dylibloader_wrapper_xlib)( char**);
-int (*XFreeFont_dylibloader_wrapper_xlib)( Display*, XFontStruct*);
-int (*XFreeFontInfo_dylibloader_wrapper_xlib)( char**, XFontStruct*, int);
-int (*XFreeFontNames_dylibloader_wrapper_xlib)( char**);
-int (*XFreeFontPath_dylibloader_wrapper_xlib)( char**);
-int (*XFreeGC_dylibloader_wrapper_xlib)( Display*, GC);
-int (*XFreeModifiermap_dylibloader_wrapper_xlib)( XModifierKeymap*);
-int (*XFreePixmap_dylibloader_wrapper_xlib)( Display*, Pixmap);
-int (*XGeometry_dylibloader_wrapper_xlib)( Display*, int,const char*,const char*, unsigned int, unsigned int, unsigned int, int, int, int*, int*, int*, int*);
-int (*XGetErrorDatabaseText_dylibloader_wrapper_xlib)( Display*,const char*,const char*,const char*, char*, int);
-int (*XGetErrorText_dylibloader_wrapper_xlib)( Display*, int, char*, int);
-int (*XGetFontProperty_dylibloader_wrapper_xlib)( XFontStruct*, Atom, unsigned long*);
-int (*XGetGCValues_dylibloader_wrapper_xlib)( Display*, GC, unsigned long, XGCValues*);
-int (*XGetGeometry_dylibloader_wrapper_xlib)( Display*, Drawable, Window*, int*, int*, unsigned int*, unsigned int*, unsigned int*, unsigned int*);
-int (*XGetIconName_dylibloader_wrapper_xlib)( Display*, Window, char**);
-int (*XGetInputFocus_dylibloader_wrapper_xlib)( Display*, Window*, int*);
-int (*XGetKeyboardControl_dylibloader_wrapper_xlib)( Display*, XKeyboardState*);
-int (*XGetPointerControl_dylibloader_wrapper_xlib)( Display*, int*, int*, int*);
-int (*XGetPointerMapping_dylibloader_wrapper_xlib)( Display*, unsigned char*, int);
-int (*XGetScreenSaver_dylibloader_wrapper_xlib)( Display*, int*, int*, int*, int*);
-int (*XGetTransientForHint_dylibloader_wrapper_xlib)( Display*, Window, Window*);
-int (*XGetWindowProperty_dylibloader_wrapper_xlib)( Display*, Window, Atom, long, long, int, Atom, Atom*, int*, unsigned long*, unsigned long*, unsigned char**);
-int (*XGetWindowAttributes_dylibloader_wrapper_xlib)( Display*, Window, XWindowAttributes*);
-int (*XGrabButton_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, Window, int, unsigned int, int, int, Window, Cursor);
-int (*XGrabKey_dylibloader_wrapper_xlib)( Display*, int, unsigned int, Window, int, int, int);
-int (*XGrabKeyboard_dylibloader_wrapper_xlib)( Display*, Window, int, int, int, Time);
-int (*XGrabPointer_dylibloader_wrapper_xlib)( Display*, Window, int, unsigned int, int, int, Window, Cursor, Time);
-int (*XGrabServer_dylibloader_wrapper_xlib)( Display*);
-int (*XHeightMMOfScreen_dylibloader_wrapper_xlib)( Screen*);
-int (*XHeightOfScreen_dylibloader_wrapper_xlib)( Screen*);
-int (*XIfEvent_dylibloader_wrapper_xlib)( Display*, XEvent*, Bool (*) (Display*, XEvent*, XPointer), XPointer);
-int (*XImageByteOrder_dylibloader_wrapper_xlib)( Display*);
-int (*XInstallColormap_dylibloader_wrapper_xlib)( Display*, Colormap);
-KeyCode (*XKeysymToKeycode_dylibloader_wrapper_xlib)( Display*, KeySym);
-int (*XKillClient_dylibloader_wrapper_xlib)( Display*, XID);
-int (*XLookupColor_dylibloader_wrapper_xlib)( Display*, Colormap,const char*, XColor*, XColor*);
-int (*XLowerWindow_dylibloader_wrapper_xlib)( Display*, Window);
-int (*XMapRaised_dylibloader_wrapper_xlib)( Display*, Window);
-int (*XMapSubwindows_dylibloader_wrapper_xlib)( Display*, Window);
-int (*XMapWindow_dylibloader_wrapper_xlib)( Display*, Window);
-int (*XMaskEvent_dylibloader_wrapper_xlib)( Display*, long, XEvent*);
-int (*XMaxCmapsOfScreen_dylibloader_wrapper_xlib)( Screen*);
-int (*XMinCmapsOfScreen_dylibloader_wrapper_xlib)( Screen*);
-int (*XMoveResizeWindow_dylibloader_wrapper_xlib)( Display*, Window, int, int, unsigned int, unsigned int);
-int (*XMoveWindow_dylibloader_wrapper_xlib)( Display*, Window, int, int);
-int (*XNextEvent_dylibloader_wrapper_xlib)( Display*, XEvent*);
-int (*XNoOp_dylibloader_wrapper_xlib)( Display*);
-int (*XParseColor_dylibloader_wrapper_xlib)( Display*, Colormap,const char*, XColor*);
-int (*XParseGeometry_dylibloader_wrapper_xlib)(const char*, int*, int*, unsigned int*, unsigned int*);
-int (*XPeekEvent_dylibloader_wrapper_xlib)( Display*, XEvent*);
-int (*XPeekIfEvent_dylibloader_wrapper_xlib)( Display*, XEvent*, Bool (*) (Display*, XEvent*, XPointer), XPointer);
-int (*XPending_dylibloader_wrapper_xlib)( Display*);
-int (*XPlanesOfScreen_dylibloader_wrapper_xlib)( Screen*);
-int (*XProtocolRevision_dylibloader_wrapper_xlib)( Display*);
-int (*XProtocolVersion_dylibloader_wrapper_xlib)( Display*);
-int (*XPutBackEvent_dylibloader_wrapper_xlib)( Display*, XEvent*);
-int (*XPutImage_dylibloader_wrapper_xlib)( Display*, Drawable, GC, XImage*, int, int, int, int, unsigned int, unsigned int);
-int (*XQLength_dylibloader_wrapper_xlib)( Display*);
-int (*XQueryBestCursor_dylibloader_wrapper_xlib)( Display*, Drawable, unsigned int, unsigned int, unsigned int*, unsigned int*);
-int (*XQueryBestSize_dylibloader_wrapper_xlib)( Display*, int, Drawable, unsigned int, unsigned int, unsigned int*, unsigned int*);
-int (*XQueryBestStipple_dylibloader_wrapper_xlib)( Display*, Drawable, unsigned int, unsigned int, unsigned int*, unsigned int*);
-int (*XQueryBestTile_dylibloader_wrapper_xlib)( Display*, Drawable, unsigned int, unsigned int, unsigned int*, unsigned int*);
-int (*XQueryColor_dylibloader_wrapper_xlib)( Display*, Colormap, XColor*);
-int (*XQueryColors_dylibloader_wrapper_xlib)( Display*, Colormap, XColor*, int);
-int (*XQueryExtension_dylibloader_wrapper_xlib)( Display*,const char*, int*, int*, int*);
-int (*XQueryKeymap_dylibloader_wrapper_xlib)( Display*, char [32]);
-int (*XQueryPointer_dylibloader_wrapper_xlib)( Display*, Window, Window*, Window*, int*, int*, int*, int*, unsigned int*);
-int (*XQueryTextExtents_dylibloader_wrapper_xlib)( Display*, XID,const char*, int, int*, int*, int*, XCharStruct*);
-int (*XQueryTextExtents16_dylibloader_wrapper_xlib)( Display*, XID,const XChar2b*, int, int*, int*, int*, XCharStruct*);
-int (*XQueryTree_dylibloader_wrapper_xlib)( Display*, Window, Window*, Window*, Window**, unsigned int*);
-int (*XRaiseWindow_dylibloader_wrapper_xlib)( Display*, Window);
-int (*XReadBitmapFile_dylibloader_wrapper_xlib)( Display*, Drawable,const char*, unsigned int*, unsigned int*, Pixmap*, int*, int*);
-int (*XReadBitmapFileData_dylibloader_wrapper_xlib)(const char*, unsigned int*, unsigned int*, unsigned char**, int*, int*);
-int (*XRebindKeysym_dylibloader_wrapper_xlib)( Display*, KeySym, KeySym*, int,const unsigned char*, int);
-int (*XRecolorCursor_dylibloader_wrapper_xlib)( Display*, Cursor, XColor*, XColor*);
-int (*XRefreshKeyboardMapping_dylibloader_wrapper_xlib)( XMappingEvent*);
-int (*XRemoveFromSaveSet_dylibloader_wrapper_xlib)( Display*, Window);
-int (*XRemoveHost_dylibloader_wrapper_xlib)( Display*, XHostAddress*);
-int (*XRemoveHosts_dylibloader_wrapper_xlib)( Display*, XHostAddress*, int);
-int (*XReparentWindow_dylibloader_wrapper_xlib)( Display*, Window, Window, int, int);
-int (*XResetScreenSaver_dylibloader_wrapper_xlib)( Display*);
-int (*XResizeWindow_dylibloader_wrapper_xlib)( Display*, Window, unsigned int, unsigned int);
-int (*XRestackWindows_dylibloader_wrapper_xlib)( Display*, Window*, int);
-int (*XRotateBuffers_dylibloader_wrapper_xlib)( Display*, int);
-int (*XRotateWindowProperties_dylibloader_wrapper_xlib)( Display*, Window, Atom*, int, int);
-int (*XScreenCount_dylibloader_wrapper_xlib)( Display*);
-int (*XSelectInput_dylibloader_wrapper_xlib)( Display*, Window, long);
-int (*XSendEvent_dylibloader_wrapper_xlib)( Display*, Window, int, long, XEvent*);
-int (*XSetAccessControl_dylibloader_wrapper_xlib)( Display*, int);
-int (*XSetArcMode_dylibloader_wrapper_xlib)( Display*, GC, int);
-int (*XSetBackground_dylibloader_wrapper_xlib)( Display*, GC, unsigned long);
-int (*XSetClipMask_dylibloader_wrapper_xlib)( Display*, GC, Pixmap);
-int (*XSetClipOrigin_dylibloader_wrapper_xlib)( Display*, GC, int, int);
-int (*XSetClipRectangles_dylibloader_wrapper_xlib)( Display*, GC, int, int, XRectangle*, int, int);
-int (*XSetCloseDownMode_dylibloader_wrapper_xlib)( Display*, int);
-int (*XSetCommand_dylibloader_wrapper_xlib)( Display*, Window, char**, int);
-int (*XSetDashes_dylibloader_wrapper_xlib)( Display*, GC, int,const char*, int);
-int (*XSetFillRule_dylibloader_wrapper_xlib)( Display*, GC, int);
-int (*XSetFillStyle_dylibloader_wrapper_xlib)( Display*, GC, int);
-int (*XSetFont_dylibloader_wrapper_xlib)( Display*, GC, Font);
-int (*XSetFontPath_dylibloader_wrapper_xlib)( Display*, char**, int);
-int (*XSetForeground_dylibloader_wrapper_xlib)( Display*, GC, unsigned long);
-int (*XSetFunction_dylibloader_wrapper_xlib)( Display*, GC, int);
-int (*XSetGraphicsExposures_dylibloader_wrapper_xlib)( Display*, GC, int);
-int (*XSetIconName_dylibloader_wrapper_xlib)( Display*, Window,const char*);
-int (*XSetInputFocus_dylibloader_wrapper_xlib)( Display*, Window, int, Time);
-int (*XSetLineAttributes_dylibloader_wrapper_xlib)( Display*, GC, unsigned int, int, int, int);
-int (*XSetModifierMapping_dylibloader_wrapper_xlib)( Display*, XModifierKeymap*);
-int (*XSetPlaneMask_dylibloader_wrapper_xlib)( Display*, GC, unsigned long);
-int (*XSetPointerMapping_dylibloader_wrapper_xlib)( Display*,const unsigned char*, int);
-int (*XSetScreenSaver_dylibloader_wrapper_xlib)( Display*, int, int, int, int);
-int (*XSetSelectionOwner_dylibloader_wrapper_xlib)( Display*, Atom, Window, Time);
-int (*XSetState_dylibloader_wrapper_xlib)( Display*, GC, unsigned long, unsigned long, int, unsigned long);
-int (*XSetStipple_dylibloader_wrapper_xlib)( Display*, GC, Pixmap);
-int (*XSetSubwindowMode_dylibloader_wrapper_xlib)( Display*, GC, int);
-int (*XSetTSOrigin_dylibloader_wrapper_xlib)( Display*, GC, int, int);
-int (*XSetTile_dylibloader_wrapper_xlib)( Display*, GC, Pixmap);
-int (*XSetWindowBackground_dylibloader_wrapper_xlib)( Display*, Window, unsigned long);
-int (*XSetWindowBackgroundPixmap_dylibloader_wrapper_xlib)( Display*, Window, Pixmap);
-int (*XSetWindowBorder_dylibloader_wrapper_xlib)( Display*, Window, unsigned long);
-int (*XSetWindowBorderPixmap_dylibloader_wrapper_xlib)( Display*, Window, Pixmap);
-int (*XSetWindowBorderWidth_dylibloader_wrapper_xlib)( Display*, Window, unsigned int);
-int (*XSetWindowColormap_dylibloader_wrapper_xlib)( Display*, Window, Colormap);
-int (*XStoreBuffer_dylibloader_wrapper_xlib)( Display*,const char*, int, int);
-int (*XStoreBytes_dylibloader_wrapper_xlib)( Display*,const char*, int);
-int (*XStoreColor_dylibloader_wrapper_xlib)( Display*, Colormap, XColor*);
-int (*XStoreColors_dylibloader_wrapper_xlib)( Display*, Colormap, XColor*, int);
-int (*XStoreName_dylibloader_wrapper_xlib)( Display*, Window,const char*);
-int (*XStoreNamedColor_dylibloader_wrapper_xlib)( Display*, Colormap,const char*, unsigned long, int);
-int (*XSync_dylibloader_wrapper_xlib)( Display*, int);
-int (*XTextExtents_dylibloader_wrapper_xlib)( XFontStruct*,const char*, int, int*, int*, int*, XCharStruct*);
-int (*XTextExtents16_dylibloader_wrapper_xlib)( XFontStruct*,const XChar2b*, int, int*, int*, int*, XCharStruct*);
-int (*XTextWidth_dylibloader_wrapper_xlib)( XFontStruct*,const char*, int);
-int (*XTextWidth16_dylibloader_wrapper_xlib)( XFontStruct*,const XChar2b*, int);
-int (*XTranslateCoordinates_dylibloader_wrapper_xlib)( Display*, Window, Window, int, int, int*, int*, Window*);
-int (*XUndefineCursor_dylibloader_wrapper_xlib)( Display*, Window);
-int (*XUngrabButton_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, Window);
-int (*XUngrabKey_dylibloader_wrapper_xlib)( Display*, int, unsigned int, Window);
-int (*XUngrabKeyboard_dylibloader_wrapper_xlib)( Display*, Time);
-int (*XUngrabPointer_dylibloader_wrapper_xlib)( Display*, Time);
-int (*XUngrabServer_dylibloader_wrapper_xlib)( Display*);
-int (*XUninstallColormap_dylibloader_wrapper_xlib)( Display*, Colormap);
-int (*XUnloadFont_dylibloader_wrapper_xlib)( Display*, Font);
-int (*XUnmapSubwindows_dylibloader_wrapper_xlib)( Display*, Window);
-int (*XUnmapWindow_dylibloader_wrapper_xlib)( Display*, Window);
-int (*XVendorRelease_dylibloader_wrapper_xlib)( Display*);
-int (*XWarpPointer_dylibloader_wrapper_xlib)( Display*, Window, Window, int, int, unsigned int, unsigned int, int, int);
-int (*XWidthMMOfScreen_dylibloader_wrapper_xlib)( Screen*);
-int (*XWidthOfScreen_dylibloader_wrapper_xlib)( Screen*);
-int (*XWindowEvent_dylibloader_wrapper_xlib)( Display*, Window, long, XEvent*);
-int (*XWriteBitmapFile_dylibloader_wrapper_xlib)( Display*,const char*, Pixmap, unsigned int, unsigned int, int, int);
-int (*XSupportsLocale_dylibloader_wrapper_xlib)( void);
-char* (*XSetLocaleModifiers_dylibloader_wrapper_xlib)(const char*);
-XOM (*XOpenOM_dylibloader_wrapper_xlib)( Display*,struct _XrmHashBucketRec*,const char*,const char*);
-int (*XCloseOM_dylibloader_wrapper_xlib)( XOM);
-char* (*XSetOMValues_dylibloader_wrapper_xlib)( XOM,...);
-char* (*XGetOMValues_dylibloader_wrapper_xlib)( XOM,...);
-Display* (*XDisplayOfOM_dylibloader_wrapper_xlib)( XOM);
-char* (*XLocaleOfOM_dylibloader_wrapper_xlib)( XOM);
-XOC (*XCreateOC_dylibloader_wrapper_xlib)( XOM,...);
-void (*XDestroyOC_dylibloader_wrapper_xlib)( XOC);
-XOM (*XOMOfOC_dylibloader_wrapper_xlib)( XOC);
-char* (*XSetOCValues_dylibloader_wrapper_xlib)( XOC,...);
-char* (*XGetOCValues_dylibloader_wrapper_xlib)( XOC,...);
-XFontSet (*XCreateFontSet_dylibloader_wrapper_xlib)( Display*,const char*, char***, int*, char**);
-void (*XFreeFontSet_dylibloader_wrapper_xlib)( Display*, XFontSet);
-int (*XFontsOfFontSet_dylibloader_wrapper_xlib)( XFontSet, XFontStruct***, char***);
-char* (*XBaseFontNameListOfFontSet_dylibloader_wrapper_xlib)( XFontSet);
-char* (*XLocaleOfFontSet_dylibloader_wrapper_xlib)( XFontSet);
-int (*XContextDependentDrawing_dylibloader_wrapper_xlib)( XFontSet);
-int (*XDirectionalDependentDrawing_dylibloader_wrapper_xlib)( XFontSet);
-int (*XContextualDrawing_dylibloader_wrapper_xlib)( XFontSet);
-XFontSetExtents* (*XExtentsOfFontSet_dylibloader_wrapper_xlib)( XFontSet);
-int (*XmbTextEscapement_dylibloader_wrapper_xlib)( XFontSet,const char*, int);
-int (*XwcTextEscapement_dylibloader_wrapper_xlib)( XFontSet,const wchar_t*, int);
-int (*Xutf8TextEscapement_dylibloader_wrapper_xlib)( XFontSet,const char*, int);
-int (*XmbTextExtents_dylibloader_wrapper_xlib)( XFontSet,const char*, int, XRectangle*, XRectangle*);
-int (*XwcTextExtents_dylibloader_wrapper_xlib)( XFontSet,const wchar_t*, int, XRectangle*, XRectangle*);
-int (*Xutf8TextExtents_dylibloader_wrapper_xlib)( XFontSet,const char*, int, XRectangle*, XRectangle*);
-int (*XmbTextPerCharExtents_dylibloader_wrapper_xlib)( XFontSet,const char*, int, XRectangle*, XRectangle*, int, int*, XRectangle*, XRectangle*);
-int (*XwcTextPerCharExtents_dylibloader_wrapper_xlib)( XFontSet,const wchar_t*, int, XRectangle*, XRectangle*, int, int*, XRectangle*, XRectangle*);
-int (*Xutf8TextPerCharExtents_dylibloader_wrapper_xlib)( XFontSet,const char*, int, XRectangle*, XRectangle*, int, int*, XRectangle*, XRectangle*);
-void (*XmbDrawText_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, XmbTextItem*, int);
-void (*XwcDrawText_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, XwcTextItem*, int);
-void (*Xutf8DrawText_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, XmbTextItem*, int);
-void (*XmbDrawString_dylibloader_wrapper_xlib)( Display*, Drawable, XFontSet, GC, int, int,const char*, int);
-void (*XwcDrawString_dylibloader_wrapper_xlib)( Display*, Drawable, XFontSet, GC, int, int,const wchar_t*, int);
-void (*Xutf8DrawString_dylibloader_wrapper_xlib)( Display*, Drawable, XFontSet, GC, int, int,const char*, int);
-void (*XmbDrawImageString_dylibloader_wrapper_xlib)( Display*, Drawable, XFontSet, GC, int, int,const char*, int);
-void (*XwcDrawImageString_dylibloader_wrapper_xlib)( Display*, Drawable, XFontSet, GC, int, int,const wchar_t*, int);
-void (*Xutf8DrawImageString_dylibloader_wrapper_xlib)( Display*, Drawable, XFontSet, GC, int, int,const char*, int);
-XIM (*XOpenIM_dylibloader_wrapper_xlib)( Display*,struct _XrmHashBucketRec*, char*, char*);
-int (*XCloseIM_dylibloader_wrapper_xlib)( XIM);
-char* (*XGetIMValues_dylibloader_wrapper_xlib)( XIM,...);
-char* (*XSetIMValues_dylibloader_wrapper_xlib)( XIM,...);
-Display* (*XDisplayOfIM_dylibloader_wrapper_xlib)( XIM);
-char* (*XLocaleOfIM_dylibloader_wrapper_xlib)( XIM);
-XIC (*XCreateIC_dylibloader_wrapper_xlib)( XIM,...);
-void (*XDestroyIC_dylibloader_wrapper_xlib)( XIC);
-void (*XSetICFocus_dylibloader_wrapper_xlib)( XIC);
-void (*XUnsetICFocus_dylibloader_wrapper_xlib)( XIC);
-wchar_t* (*XwcResetIC_dylibloader_wrapper_xlib)( XIC);
-char* (*XmbResetIC_dylibloader_wrapper_xlib)( XIC);
-char* (*Xutf8ResetIC_dylibloader_wrapper_xlib)( XIC);
-char* (*XSetICValues_dylibloader_wrapper_xlib)( XIC,...);
-char* (*XGetICValues_dylibloader_wrapper_xlib)( XIC,...);
-XIM (*XIMOfIC_dylibloader_wrapper_xlib)( XIC);
-int (*XFilterEvent_dylibloader_wrapper_xlib)( XEvent*, Window);
-int (*XmbLookupString_dylibloader_wrapper_xlib)( XIC, XKeyPressedEvent*, char*, int, KeySym*, int*);
-int (*XwcLookupString_dylibloader_wrapper_xlib)( XIC, XKeyPressedEvent*, wchar_t*, int, KeySym*, int*);
-int (*Xutf8LookupString_dylibloader_wrapper_xlib)( XIC, XKeyPressedEvent*, char*, int, KeySym*, int*);
-XVaNestedList (*XVaCreateNestedList_dylibloader_wrapper_xlib)( int,...);
-int (*XRegisterIMInstantiateCallback_dylibloader_wrapper_xlib)( Display*,struct _XrmHashBucketRec*, char*, char*, XIDProc, XPointer);
-int (*XUnregisterIMInstantiateCallback_dylibloader_wrapper_xlib)( Display*,struct _XrmHashBucketRec*, char*, char*, XIDProc, XPointer);
-int (*XInternalConnectionNumbers_dylibloader_wrapper_xlib)( Display*, int**, int*);
-void (*XProcessInternalConnection_dylibloader_wrapper_xlib)( Display*, int);
-int (*XAddConnectionWatch_dylibloader_wrapper_xlib)( Display*, XConnectionWatchProc, XPointer);
-void (*XRemoveConnectionWatch_dylibloader_wrapper_xlib)( Display*, XConnectionWatchProc, XPointer);
-void (*XSetAuthorization_dylibloader_wrapper_xlib)( char*, int, char*, int);
-int (*_Xmbtowc_dylibloader_wrapper_xlib)( wchar_t*, char*, int);
-int (*_Xwctomb_dylibloader_wrapper_xlib)( char*, wchar_t);
-int (*XGetEventData_dylibloader_wrapper_xlib)( Display*, XGenericEventCookie*);
-void (*XFreeEventData_dylibloader_wrapper_xlib)( Display*, XGenericEventCookie*);
-XClassHint* (*XAllocClassHint_dylibloader_wrapper_xlib)( void);
-XIconSize* (*XAllocIconSize_dylibloader_wrapper_xlib)( void);
-XSizeHints* (*XAllocSizeHints_dylibloader_wrapper_xlib)( void);
-XStandardColormap* (*XAllocStandardColormap_dylibloader_wrapper_xlib)( void);
-XWMHints* (*XAllocWMHints_dylibloader_wrapper_xlib)( void);
-int (*XClipBox_dylibloader_wrapper_xlib)( Region, XRectangle*);
-Region (*XCreateRegion_dylibloader_wrapper_xlib)( void);
-const char* (*XDefaultString_dylibloader_wrapper_xlib)( void);
-int (*XDeleteContext_dylibloader_wrapper_xlib)( Display*, XID, XContext);
-int (*XDestroyRegion_dylibloader_wrapper_xlib)( Region);
-int (*XEmptyRegion_dylibloader_wrapper_xlib)( Region);
-int (*XEqualRegion_dylibloader_wrapper_xlib)( Region, Region);
-int (*XFindContext_dylibloader_wrapper_xlib)( Display*, XID, XContext, XPointer*);
-int (*XGetClassHint_dylibloader_wrapper_xlib)( Display*, Window, XClassHint*);
-int (*XGetIconSizes_dylibloader_wrapper_xlib)( Display*, Window, XIconSize**, int*);
-int (*XGetNormalHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*);
-int (*XGetRGBColormaps_dylibloader_wrapper_xlib)( Display*, Window, XStandardColormap**, int*, Atom);
-int (*XGetSizeHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*, Atom);
-int (*XGetStandardColormap_dylibloader_wrapper_xlib)( Display*, Window, XStandardColormap*, Atom);
-int (*XGetTextProperty_dylibloader_wrapper_xlib)( Display*, Window, XTextProperty*, Atom);
-XVisualInfo* (*XGetVisualInfo_dylibloader_wrapper_xlib)( Display*, long, XVisualInfo*, int*);
-int (*XGetWMClientMachine_dylibloader_wrapper_xlib)( Display*, Window, XTextProperty*);
-XWMHints* (*XGetWMHints_dylibloader_wrapper_xlib)( Display*, Window);
-int (*XGetWMIconName_dylibloader_wrapper_xlib)( Display*, Window, XTextProperty*);
-int (*XGetWMName_dylibloader_wrapper_xlib)( Display*, Window, XTextProperty*);
-int (*XGetWMNormalHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*, long*);
-int (*XGetWMSizeHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*, long*, Atom);
-int (*XGetZoomHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*);
-int (*XIntersectRegion_dylibloader_wrapper_xlib)( Region, Region, Region);
-void (*XConvertCase_dylibloader_wrapper_xlib)( KeySym, KeySym*, KeySym*);
-int (*XLookupString_dylibloader_wrapper_xlib)( XKeyEvent*, char*, int, KeySym*, XComposeStatus*);
-int (*XMatchVisualInfo_dylibloader_wrapper_xlib)( Display*, int, int, int, XVisualInfo*);
-int (*XOffsetRegion_dylibloader_wrapper_xlib)( Region, int, int);
-int (*XPointInRegion_dylibloader_wrapper_xlib)( Region, int, int);
-Region (*XPolygonRegion_dylibloader_wrapper_xlib)( XPoint*, int, int);
-int (*XRectInRegion_dylibloader_wrapper_xlib)( Region, int, int, unsigned int, unsigned int);
-int (*XSaveContext_dylibloader_wrapper_xlib)( Display*, XID, XContext,const char*);
-int (*XSetClassHint_dylibloader_wrapper_xlib)( Display*, Window, XClassHint*);
-int (*XSetIconSizes_dylibloader_wrapper_xlib)( Display*, Window, XIconSize*, int);
-int (*XSetNormalHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*);
-void (*XSetRGBColormaps_dylibloader_wrapper_xlib)( Display*, Window, XStandardColormap*, int, Atom);
-int (*XSetSizeHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*, Atom);
-int (*XSetStandardProperties_dylibloader_wrapper_xlib)( Display*, Window,const char*,const char*, Pixmap, char**, int, XSizeHints*);
-void (*XSetTextProperty_dylibloader_wrapper_xlib)( Display*, Window, XTextProperty*, Atom);
-void (*XSetWMClientMachine_dylibloader_wrapper_xlib)( Display*, Window, XTextProperty*);
-int (*XSetWMHints_dylibloader_wrapper_xlib)( Display*, Window, XWMHints*);
-void (*XSetWMIconName_dylibloader_wrapper_xlib)( Display*, Window, XTextProperty*);
-void (*XSetWMName_dylibloader_wrapper_xlib)( Display*, Window, XTextProperty*);
-void (*XSetWMNormalHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*);
-void (*XSetWMProperties_dylibloader_wrapper_xlib)( Display*, Window, XTextProperty*, XTextProperty*, char**, int, XSizeHints*, XWMHints*, XClassHint*);
-void (*XmbSetWMProperties_dylibloader_wrapper_xlib)( Display*, Window,const char*,const char*, char**, int, XSizeHints*, XWMHints*, XClassHint*);
-void (*Xutf8SetWMProperties_dylibloader_wrapper_xlib)( Display*, Window,const char*,const char*, char**, int, XSizeHints*, XWMHints*, XClassHint*);
-void (*XSetWMSizeHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*, Atom);
-int (*XSetRegion_dylibloader_wrapper_xlib)( Display*, GC, Region);
-void (*XSetStandardColormap_dylibloader_wrapper_xlib)( Display*, Window, XStandardColormap*, Atom);
-int (*XSetZoomHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*);
-int (*XShrinkRegion_dylibloader_wrapper_xlib)( Region, int, int);
-int (*XStringListToTextProperty_dylibloader_wrapper_xlib)( char**, int, XTextProperty*);
-int (*XSubtractRegion_dylibloader_wrapper_xlib)( Region, Region, Region);
-int (*XmbTextListToTextProperty_dylibloader_wrapper_xlib)( Display*, char**, int, XICCEncodingStyle, XTextProperty*);
-int (*XwcTextListToTextProperty_dylibloader_wrapper_xlib)( Display*, wchar_t**, int, XICCEncodingStyle, XTextProperty*);
-int (*Xutf8TextListToTextProperty_dylibloader_wrapper_xlib)( Display*, char**, int, XICCEncodingStyle, XTextProperty*);
-void (*XwcFreeStringList_dylibloader_wrapper_xlib)( wchar_t**);
-int (*XTextPropertyToStringList_dylibloader_wrapper_xlib)( XTextProperty*, char***, int*);
-int (*XmbTextPropertyToTextList_dylibloader_wrapper_xlib)( Display*,const XTextProperty*, char***, int*);
-int (*XwcTextPropertyToTextList_dylibloader_wrapper_xlib)( Display*,const XTextProperty*, wchar_t***, int*);
-int (*Xutf8TextPropertyToTextList_dylibloader_wrapper_xlib)( Display*,const XTextProperty*, char***, int*);
-int (*XUnionRectWithRegion_dylibloader_wrapper_xlib)( XRectangle*, Region, Region);
-int (*XUnionRegion_dylibloader_wrapper_xlib)( Region, Region, Region);
-int (*XWMGeometry_dylibloader_wrapper_xlib)( Display*, int,const char*,const char*, unsigned int, XSizeHints*, int*, int*, int*, int*, int*);
-int (*XXorRegion_dylibloader_wrapper_xlib)( Region, Region, Region);
-int (*XkbIgnoreExtension_dylibloader_wrapper_xlib)( int);
-Display* (*XkbOpenDisplay_dylibloader_wrapper_xlib)( char*, int*, int*, int*, int*, int*);
-int (*XkbQueryExtension_dylibloader_wrapper_xlib)( Display*, int*, int*, int*, int*, int*);
-int (*XkbUseExtension_dylibloader_wrapper_xlib)( Display*, int*, int*);
-int (*XkbLibraryVersion_dylibloader_wrapper_xlib)( int*, int*);
-unsigned int (*XkbSetXlibControls_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int);
-unsigned int (*XkbGetXlibControls_dylibloader_wrapper_xlib)( Display*);
-unsigned int (*XkbXlibControlsImplemented_dylibloader_wrapper_xlib)( void);
-void (*XkbSetAtomFuncs_dylibloader_wrapper_xlib)( XkbInternAtomFunc, XkbGetAtomNameFunc);
-KeySym (*XkbKeycodeToKeysym_dylibloader_wrapper_xlib)( Display*, KeyCode, int, int);
-unsigned int (*XkbKeysymToModifiers_dylibloader_wrapper_xlib)( Display*, KeySym);
-int (*XkbLookupKeySym_dylibloader_wrapper_xlib)( Display*, KeyCode, unsigned int, unsigned int*, KeySym*);
-int (*XkbLookupKeyBinding_dylibloader_wrapper_xlib)( Display*, KeySym, unsigned int, char*, int, int*);
-int (*XkbTranslateKeyCode_dylibloader_wrapper_xlib)( XkbDescPtr, KeyCode, unsigned int, unsigned int*, KeySym*);
-int (*XkbTranslateKeySym_dylibloader_wrapper_xlib)( Display*, KeySym*, unsigned int, char*, int, int*);
-int (*XkbSetAutoRepeatRate_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int);
-int (*XkbGetAutoRepeatRate_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int*, unsigned int*);
-int (*XkbChangeEnabledControls_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int);
-int (*XkbDeviceBell_dylibloader_wrapper_xlib)( Display*, Window, int, int, int, int, Atom);
-int (*XkbForceDeviceBell_dylibloader_wrapper_xlib)( Display*, int, int, int, int);
-int (*XkbDeviceBellEvent_dylibloader_wrapper_xlib)( Display*, Window, int, int, int, int, Atom);
-int (*XkbBell_dylibloader_wrapper_xlib)( Display*, Window, int, Atom);
-int (*XkbForceBell_dylibloader_wrapper_xlib)( Display*, int);
-int (*XkbBellEvent_dylibloader_wrapper_xlib)( Display*, Window, int, Atom);
-int (*XkbSelectEvents_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int);
-int (*XkbSelectEventDetails_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned long, unsigned long);
-void (*XkbNoteMapChanges_dylibloader_wrapper_xlib)( XkbMapChangesPtr, XkbMapNotifyEvent*, unsigned int);
-void (*XkbNoteNameChanges_dylibloader_wrapper_xlib)( XkbNameChangesPtr, XkbNamesNotifyEvent*, unsigned int);
-int (*XkbGetIndicatorState_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int*);
-int (*XkbGetIndicatorMap_dylibloader_wrapper_xlib)( Display*, unsigned long, XkbDescPtr);
-int (*XkbSetIndicatorMap_dylibloader_wrapper_xlib)( Display*, unsigned long, XkbDescPtr);
-int (*XkbGetNamedIndicator_dylibloader_wrapper_xlib)( Display*, Atom, int*, int*, XkbIndicatorMapPtr, int*);
-int (*XkbGetNamedDeviceIndicator_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int, Atom, int*, int*, XkbIndicatorMapPtr, int*);
-int (*XkbSetNamedIndicator_dylibloader_wrapper_xlib)( Display*, Atom, int, int, int, XkbIndicatorMapPtr);
-int (*XkbSetNamedDeviceIndicator_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int, Atom, int, int, int, XkbIndicatorMapPtr);
-int (*XkbLockModifiers_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int);
-int (*XkbLatchModifiers_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int);
-int (*XkbLockGroup_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int);
-int (*XkbLatchGroup_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int);
-int (*XkbSetServerInternalMods_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int);
-int (*XkbSetIgnoreLockMods_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int);
-int (*XkbVirtualModsToReal_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, unsigned int*);
-int (*XkbComputeEffectiveMap_dylibloader_wrapper_xlib)( XkbDescPtr, XkbKeyTypePtr, unsigned char*);
-int (*XkbInitCanonicalKeyTypes_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, int);
-XkbDescPtr (*XkbAllocKeyboard_dylibloader_wrapper_xlib)( void);
-void (*XkbFreeKeyboard_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, int);
-int (*XkbAllocClientMap_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, unsigned int);
-int (*XkbAllocServerMap_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, unsigned int);
-void (*XkbFreeClientMap_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, int);
-void (*XkbFreeServerMap_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, int);
-XkbKeyTypePtr (*XkbAddKeyType_dylibloader_wrapper_xlib)( XkbDescPtr, Atom, int, int, int);
-int (*XkbAllocIndicatorMaps_dylibloader_wrapper_xlib)( XkbDescPtr);
-void (*XkbFreeIndicatorMaps_dylibloader_wrapper_xlib)( XkbDescPtr);
-XkbDescPtr (*XkbGetMap_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int);
-int (*XkbGetUpdatedMap_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbDescPtr);
-int (*XkbGetMapChanges_dylibloader_wrapper_xlib)( Display*, XkbDescPtr, XkbMapChangesPtr);
-int (*XkbRefreshKeyboardMapping_dylibloader_wrapper_xlib)( XkbMapNotifyEvent*);
-int (*XkbGetKeyTypes_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, XkbDescPtr);
-int (*XkbGetKeySyms_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, XkbDescPtr);
-int (*XkbGetKeyActions_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, XkbDescPtr);
-int (*XkbGetKeyBehaviors_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, XkbDescPtr);
-int (*XkbGetVirtualMods_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbDescPtr);
-int (*XkbGetKeyExplicitComponents_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, XkbDescPtr);
-int (*XkbGetKeyModifierMap_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, XkbDescPtr);
-int (*XkbGetKeyVirtualModMap_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, XkbDescPtr);
-int (*XkbAllocControls_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int);
-void (*XkbFreeControls_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, int);
-int (*XkbGetControls_dylibloader_wrapper_xlib)( Display*, unsigned long, XkbDescPtr);
-int (*XkbSetControls_dylibloader_wrapper_xlib)( Display*, unsigned long, XkbDescPtr);
-void (*XkbNoteControlsChanges_dylibloader_wrapper_xlib)( XkbControlsChangesPtr, XkbControlsNotifyEvent*, unsigned int);
-int (*XkbAllocCompatMap_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, unsigned int);
-void (*XkbFreeCompatMap_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, int);
-int (*XkbGetCompatMap_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbDescPtr);
-int (*XkbSetCompatMap_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbDescPtr, int);
-int (*XkbAllocNames_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, int, int);
-int (*XkbGetNames_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbDescPtr);
-int (*XkbSetNames_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int, XkbDescPtr);
-int (*XkbChangeNames_dylibloader_wrapper_xlib)( Display*, XkbDescPtr, XkbNameChangesPtr);
-void (*XkbFreeNames_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, int);
-int (*XkbGetState_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbStatePtr);
-int (*XkbSetMap_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbDescPtr);
-int (*XkbChangeMap_dylibloader_wrapper_xlib)( Display*, XkbDescPtr, XkbMapChangesPtr);
-int (*XkbSetDetectableAutoRepeat_dylibloader_wrapper_xlib)( Display*, int, int*);
-int (*XkbGetDetectableAutoRepeat_dylibloader_wrapper_xlib)( Display*, int*);
-int (*XkbSetAutoResetControls_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int*, unsigned int*);
-int (*XkbGetAutoResetControls_dylibloader_wrapper_xlib)( Display*, unsigned int*, unsigned int*);
-int (*XkbSetPerClientControls_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int*);
-int (*XkbGetPerClientControls_dylibloader_wrapper_xlib)( Display*, unsigned int*);
-int (*XkbCopyKeyType_dylibloader_wrapper_xlib)( XkbKeyTypePtr, XkbKeyTypePtr);
-int (*XkbCopyKeyTypes_dylibloader_wrapper_xlib)( XkbKeyTypePtr, XkbKeyTypePtr, int);
-int (*XkbResizeKeyType_dylibloader_wrapper_xlib)( XkbDescPtr, int, int, int, int);
-KeySym* (*XkbResizeKeySyms_dylibloader_wrapper_xlib)( XkbDescPtr, int, int);
-XkbAction* (*XkbResizeKeyActions_dylibloader_wrapper_xlib)( XkbDescPtr, int, int);
-int (*XkbChangeTypesOfKey_dylibloader_wrapper_xlib)( XkbDescPtr, int, int, unsigned int, int*, XkbMapChangesPtr);
-int (*XkbChangeKeycodeRange_dylibloader_wrapper_xlib)( XkbDescPtr, int, int, XkbChangesPtr);
-XkbComponentListPtr (*XkbListComponents_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbComponentNamesPtr, int*);
-void (*XkbFreeComponentList_dylibloader_wrapper_xlib)( XkbComponentListPtr);
-XkbDescPtr (*XkbGetKeyboard_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int);
-XkbDescPtr (*XkbGetKeyboardByName_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbComponentNamesPtr, unsigned int, unsigned int, int);
-int (*XkbKeyTypesForCoreSymbols_dylibloader_wrapper_xlib)( XkbDescPtr, int, KeySym*, unsigned int, int*, KeySym*);
-int (*XkbApplyCompatMapToKey_dylibloader_wrapper_xlib)( XkbDescPtr, KeyCode, XkbChangesPtr);
-int (*XkbUpdateMapFromCore_dylibloader_wrapper_xlib)( XkbDescPtr, KeyCode, int, int, KeySym*, XkbChangesPtr);
-XkbDeviceLedInfoPtr (*XkbAddDeviceLedInfo_dylibloader_wrapper_xlib)( XkbDeviceInfoPtr, unsigned int, unsigned int);
-int (*XkbResizeDeviceButtonActions_dylibloader_wrapper_xlib)( XkbDeviceInfoPtr, unsigned int);
-XkbDeviceInfoPtr (*XkbAllocDeviceInfo_dylibloader_wrapper_xlib)( unsigned int, unsigned int, unsigned int);
-void (*XkbFreeDeviceInfo_dylibloader_wrapper_xlib)( XkbDeviceInfoPtr, unsigned int, int);
-void (*XkbNoteDeviceChanges_dylibloader_wrapper_xlib)( XkbDeviceChangesPtr, XkbExtensionDeviceNotifyEvent*, unsigned int);
-XkbDeviceInfoPtr (*XkbGetDeviceInfo_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int, unsigned int);
-int (*XkbGetDeviceInfoChanges_dylibloader_wrapper_xlib)( Display*, XkbDeviceInfoPtr, XkbDeviceChangesPtr);
-int (*XkbGetDeviceButtonActions_dylibloader_wrapper_xlib)( Display*, XkbDeviceInfoPtr, int, unsigned int, unsigned int);
-int (*XkbGetDeviceLedInfo_dylibloader_wrapper_xlib)( Display*, XkbDeviceInfoPtr, unsigned int, unsigned int, unsigned int);
-int (*XkbSetDeviceInfo_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbDeviceInfoPtr);
-int (*XkbChangeDeviceInfo_dylibloader_wrapper_xlib)( Display*, XkbDeviceInfoPtr, XkbDeviceChangesPtr);
-int (*XkbSetDeviceLedInfo_dylibloader_wrapper_xlib)( Display*, XkbDeviceInfoPtr, unsigned int, unsigned int, unsigned int);
-int (*XkbSetDeviceButtonActions_dylibloader_wrapper_xlib)( Display*, XkbDeviceInfoPtr, unsigned int, unsigned int);
-char (*XkbToControl_dylibloader_wrapper_xlib)( char);
-int (*XkbSetDebuggingFlags_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, char*, unsigned int, unsigned int, unsigned int*, unsigned int*);
-int (*XkbApplyVirtualModChanges_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, XkbChangesPtr);
-int (*XkbUpdateActionVirtualMods_dylibloader_wrapper_xlib)( XkbDescPtr, XkbAction*, unsigned int);
-void (*XkbUpdateKeyTypeVirtualMods_dylibloader_wrapper_xlib)( XkbDescPtr, XkbKeyTypePtr, unsigned int, XkbChangesPtr);
+int (*_Xmblen_dylibloader_wrapper_xlib)(char *, int);
+XFontStruct *(*XLoadQueryFont_dylibloader_wrapper_xlib)(Display *, const char *);
+XFontStruct *(*XQueryFont_dylibloader_wrapper_xlib)(Display *, XID);
+XTimeCoord *(*XGetMotionEvents_dylibloader_wrapper_xlib)(Display *, Window, Time, Time, int *);
+XModifierKeymap *(*XDeleteModifiermapEntry_dylibloader_wrapper_xlib)(XModifierKeymap *, KeyCode, int);
+XModifierKeymap *(*XGetModifierMapping_dylibloader_wrapper_xlib)(Display *);
+XModifierKeymap *(*XInsertModifiermapEntry_dylibloader_wrapper_xlib)(XModifierKeymap *, KeyCode, int);
+XModifierKeymap *(*XNewModifiermap_dylibloader_wrapper_xlib)(int);
+XImage *(*XCreateImage_dylibloader_wrapper_xlib)(Display *, Visual *, unsigned int, int, int, char *, unsigned int, unsigned int, int, int);
+int (*XInitImage_dylibloader_wrapper_xlib)(XImage *);
+XImage *(*XGetImage_dylibloader_wrapper_xlib)(Display *, Drawable, int, int, unsigned int, unsigned int, unsigned long, int);
+XImage *(*XGetSubImage_dylibloader_wrapper_xlib)(Display *, Drawable, int, int, unsigned int, unsigned int, unsigned long, int, XImage *, int, int);
+Display *(*XOpenDisplay_dylibloader_wrapper_xlib)(const char *);
+void (*XrmInitialize_dylibloader_wrapper_xlib)(void);
+char *(*XFetchBytes_dylibloader_wrapper_xlib)(Display *, int *);
+char *(*XFetchBuffer_dylibloader_wrapper_xlib)(Display *, int *, int);
+char *(*XGetAtomName_dylibloader_wrapper_xlib)(Display *, Atom);
+int (*XGetAtomNames_dylibloader_wrapper_xlib)(Display *, Atom *, int, char **);
+char *(*XGetDefault_dylibloader_wrapper_xlib)(Display *, const char *, const char *);
+char *(*XDisplayName_dylibloader_wrapper_xlib)(const char *);
+char *(*XKeysymToString_dylibloader_wrapper_xlib)(KeySym);
+int (*(*XSynchronize_dylibloader_wrapper_xlib)(Display *, int))(Display *);
+int (*(*XSetAfterFunction_dylibloader_wrapper_xlib)(Display *, int (*)(Display *)))(Display *);
+Atom (*XInternAtom_dylibloader_wrapper_xlib)(Display *, const char *, int);
+int (*XInternAtoms_dylibloader_wrapper_xlib)(Display *, char **, int, int, Atom *);
+Colormap (*XCopyColormapAndFree_dylibloader_wrapper_xlib)(Display *, Colormap);
+Colormap (*XCreateColormap_dylibloader_wrapper_xlib)(Display *, Window, Visual *, int);
+Cursor (*XCreatePixmapCursor_dylibloader_wrapper_xlib)(Display *, Pixmap, Pixmap, XColor *, XColor *, unsigned int, unsigned int);
+Cursor (*XCreateGlyphCursor_dylibloader_wrapper_xlib)(Display *, Font, Font, unsigned int, unsigned int, const XColor *, const XColor *);
+Cursor (*XCreateFontCursor_dylibloader_wrapper_xlib)(Display *, unsigned int);
+Font (*XLoadFont_dylibloader_wrapper_xlib)(Display *, const char *);
+GC (*XCreateGC_dylibloader_wrapper_xlib)(Display *, Drawable, unsigned long, XGCValues *);
+GContext (*XGContextFromGC_dylibloader_wrapper_xlib)(GC);
+void (*XFlushGC_dylibloader_wrapper_xlib)(Display *, GC);
+Pixmap (*XCreatePixmap_dylibloader_wrapper_xlib)(Display *, Drawable, unsigned int, unsigned int, unsigned int);
+Pixmap (*XCreateBitmapFromData_dylibloader_wrapper_xlib)(Display *, Drawable, const char *, unsigned int, unsigned int);
+Pixmap (*XCreatePixmapFromBitmapData_dylibloader_wrapper_xlib)(Display *, Drawable, char *, unsigned int, unsigned int, unsigned long, unsigned long, unsigned int);
+Window (*XCreateSimpleWindow_dylibloader_wrapper_xlib)(Display *, Window, int, int, unsigned int, unsigned int, unsigned int, unsigned long, unsigned long);
+Window (*XGetSelectionOwner_dylibloader_wrapper_xlib)(Display *, Atom);
+Window (*XCreateWindow_dylibloader_wrapper_xlib)(Display *, Window, int, int, unsigned int, unsigned int, unsigned int, int, unsigned int, Visual *, unsigned long, XSetWindowAttributes *);
+Colormap *(*XListInstalledColormaps_dylibloader_wrapper_xlib)(Display *, Window, int *);
+char **(*XListFonts_dylibloader_wrapper_xlib)(Display *, const char *, int, int *);
+char **(*XListFontsWithInfo_dylibloader_wrapper_xlib)(Display *, const char *, int, int *, XFontStruct **);
+char **(*XGetFontPath_dylibloader_wrapper_xlib)(Display *, int *);
+char **(*XListExtensions_dylibloader_wrapper_xlib)(Display *, int *);
+Atom *(*XListProperties_dylibloader_wrapper_xlib)(Display *, Window, int *);
+XHostAddress *(*XListHosts_dylibloader_wrapper_xlib)(Display *, int *, int *);
+KeySym (*XKeycodeToKeysym_dylibloader_wrapper_xlib)(Display *, KeyCode, int);
+KeySym (*XLookupKeysym_dylibloader_wrapper_xlib)(XKeyEvent *, int);
+KeySym *(*XGetKeyboardMapping_dylibloader_wrapper_xlib)(Display *, KeyCode, int, int *);
+KeySym (*XStringToKeysym_dylibloader_wrapper_xlib)(const char *);
+long (*XMaxRequestSize_dylibloader_wrapper_xlib)(Display *);
+long (*XExtendedMaxRequestSize_dylibloader_wrapper_xlib)(Display *);
+char *(*XResourceManagerString_dylibloader_wrapper_xlib)(Display *);
+char *(*XScreenResourceString_dylibloader_wrapper_xlib)(Screen *);
+unsigned long (*XDisplayMotionBufferSize_dylibloader_wrapper_xlib)(Display *);
+VisualID (*XVisualIDFromVisual_dylibloader_wrapper_xlib)(Visual *);
+int (*XInitThreads_dylibloader_wrapper_xlib)(void);
+void (*XLockDisplay_dylibloader_wrapper_xlib)(Display *);
+void (*XUnlockDisplay_dylibloader_wrapper_xlib)(Display *);
+XExtCodes *(*XInitExtension_dylibloader_wrapper_xlib)(Display *, const char *);
+XExtCodes *(*XAddExtension_dylibloader_wrapper_xlib)(Display *);
+XExtData *(*XFindOnExtensionList_dylibloader_wrapper_xlib)(XExtData **, int);
+XExtData **(*XEHeadOfExtensionList_dylibloader_wrapper_xlib)(XEDataObject);
+Window (*XRootWindow_dylibloader_wrapper_xlib)(Display *, int);
+Window (*XDefaultRootWindow_dylibloader_wrapper_xlib)(Display *);
+Window (*XRootWindowOfScreen_dylibloader_wrapper_xlib)(Screen *);
+Visual *(*XDefaultVisual_dylibloader_wrapper_xlib)(Display *, int);
+Visual *(*XDefaultVisualOfScreen_dylibloader_wrapper_xlib)(Screen *);
+GC (*XDefaultGC_dylibloader_wrapper_xlib)(Display *, int);
+GC (*XDefaultGCOfScreen_dylibloader_wrapper_xlib)(Screen *);
+unsigned long (*XBlackPixel_dylibloader_wrapper_xlib)(Display *, int);
+unsigned long (*XWhitePixel_dylibloader_wrapper_xlib)(Display *, int);
+unsigned long (*XAllPlanes_dylibloader_wrapper_xlib)(void);
+unsigned long (*XBlackPixelOfScreen_dylibloader_wrapper_xlib)(Screen *);
+unsigned long (*XWhitePixelOfScreen_dylibloader_wrapper_xlib)(Screen *);
+unsigned long (*XNextRequest_dylibloader_wrapper_xlib)(Display *);
+unsigned long (*XLastKnownRequestProcessed_dylibloader_wrapper_xlib)(Display *);
+char *(*XServerVendor_dylibloader_wrapper_xlib)(Display *);
+char *(*XDisplayString_dylibloader_wrapper_xlib)(Display *);
+Colormap (*XDefaultColormap_dylibloader_wrapper_xlib)(Display *, int);
+Colormap (*XDefaultColormapOfScreen_dylibloader_wrapper_xlib)(Screen *);
+Display *(*XDisplayOfScreen_dylibloader_wrapper_xlib)(Screen *);
+Screen *(*XScreenOfDisplay_dylibloader_wrapper_xlib)(Display *, int);
+Screen *(*XDefaultScreenOfDisplay_dylibloader_wrapper_xlib)(Display *);
+long (*XEventMaskOfScreen_dylibloader_wrapper_xlib)(Screen *);
+int (*XScreenNumberOfScreen_dylibloader_wrapper_xlib)(Screen *);
+XErrorHandler (*XSetErrorHandler_dylibloader_wrapper_xlib)(XErrorHandler);
+XIOErrorHandler (*XSetIOErrorHandler_dylibloader_wrapper_xlib)(XIOErrorHandler);
+void (*XSetIOErrorExitHandler_dylibloader_wrapper_xlib)(Display *, XIOErrorExitHandler, void *);
+XPixmapFormatValues *(*XListPixmapFormats_dylibloader_wrapper_xlib)(Display *, int *);
+int *(*XListDepths_dylibloader_wrapper_xlib)(Display *, int, int *);
+int (*XReconfigureWMWindow_dylibloader_wrapper_xlib)(Display *, Window, int, unsigned int, XWindowChanges *);
+int (*XGetWMProtocols_dylibloader_wrapper_xlib)(Display *, Window, Atom **, int *);
+int (*XSetWMProtocols_dylibloader_wrapper_xlib)(Display *, Window, Atom *, int);
+int (*XIconifyWindow_dylibloader_wrapper_xlib)(Display *, Window, int);
+int (*XWithdrawWindow_dylibloader_wrapper_xlib)(Display *, Window, int);
+int (*XGetCommand_dylibloader_wrapper_xlib)(Display *, Window, char ***, int *);
+int (*XGetWMColormapWindows_dylibloader_wrapper_xlib)(Display *, Window, Window **, int *);
+int (*XSetWMColormapWindows_dylibloader_wrapper_xlib)(Display *, Window, Window *, int);
+void (*XFreeStringList_dylibloader_wrapper_xlib)(char **);
+int (*XSetTransientForHint_dylibloader_wrapper_xlib)(Display *, Window, Window);
+int (*XActivateScreenSaver_dylibloader_wrapper_xlib)(Display *);
+int (*XAddHost_dylibloader_wrapper_xlib)(Display *, XHostAddress *);
+int (*XAddHosts_dylibloader_wrapper_xlib)(Display *, XHostAddress *, int);
+int (*XAddToExtensionList_dylibloader_wrapper_xlib)(struct _XExtData **, XExtData *);
+int (*XAddToSaveSet_dylibloader_wrapper_xlib)(Display *, Window);
+int (*XAllocColor_dylibloader_wrapper_xlib)(Display *, Colormap, XColor *);
+int (*XAllocColorCells_dylibloader_wrapper_xlib)(Display *, Colormap, int, unsigned long *, unsigned int, unsigned long *, unsigned int);
+int (*XAllocColorPlanes_dylibloader_wrapper_xlib)(Display *, Colormap, int, unsigned long *, int, int, int, int, unsigned long *, unsigned long *, unsigned long *);
+int (*XAllocNamedColor_dylibloader_wrapper_xlib)(Display *, Colormap, const char *, XColor *, XColor *);
+int (*XAllowEvents_dylibloader_wrapper_xlib)(Display *, int, Time);
+int (*XAutoRepeatOff_dylibloader_wrapper_xlib)(Display *);
+int (*XAutoRepeatOn_dylibloader_wrapper_xlib)(Display *);
+int (*XBell_dylibloader_wrapper_xlib)(Display *, int);
+int (*XBitmapBitOrder_dylibloader_wrapper_xlib)(Display *);
+int (*XBitmapPad_dylibloader_wrapper_xlib)(Display *);
+int (*XBitmapUnit_dylibloader_wrapper_xlib)(Display *);
+int (*XCellsOfScreen_dylibloader_wrapper_xlib)(Screen *);
+int (*XChangeActivePointerGrab_dylibloader_wrapper_xlib)(Display *, unsigned int, Cursor, Time);
+int (*XChangeGC_dylibloader_wrapper_xlib)(Display *, GC, unsigned long, XGCValues *);
+int (*XChangeKeyboardControl_dylibloader_wrapper_xlib)(Display *, unsigned long, XKeyboardControl *);
+int (*XChangeKeyboardMapping_dylibloader_wrapper_xlib)(Display *, int, int, KeySym *, int);
+int (*XChangePointerControl_dylibloader_wrapper_xlib)(Display *, int, int, int, int, int);
+int (*XChangeProperty_dylibloader_wrapper_xlib)(Display *, Window, Atom, Atom, int, int, const unsigned char *, int);
+int (*XChangeSaveSet_dylibloader_wrapper_xlib)(Display *, Window, int);
+int (*XChangeWindowAttributes_dylibloader_wrapper_xlib)(Display *, Window, unsigned long, XSetWindowAttributes *);
+int (*XCheckIfEvent_dylibloader_wrapper_xlib)(Display *, XEvent *, int (*)(Display *, XEvent *, XPointer), XPointer);
+int (*XCheckMaskEvent_dylibloader_wrapper_xlib)(Display *, long, XEvent *);
+int (*XCheckTypedEvent_dylibloader_wrapper_xlib)(Display *, int, XEvent *);
+int (*XCheckTypedWindowEvent_dylibloader_wrapper_xlib)(Display *, Window, int, XEvent *);
+int (*XCheckWindowEvent_dylibloader_wrapper_xlib)(Display *, Window, long, XEvent *);
+int (*XCirculateSubwindows_dylibloader_wrapper_xlib)(Display *, Window, int);
+int (*XCirculateSubwindowsDown_dylibloader_wrapper_xlib)(Display *, Window);
+int (*XCirculateSubwindowsUp_dylibloader_wrapper_xlib)(Display *, Window);
+int (*XClearArea_dylibloader_wrapper_xlib)(Display *, Window, int, int, unsigned int, unsigned int, int);
+int (*XClearWindow_dylibloader_wrapper_xlib)(Display *, Window);
+int (*XCloseDisplay_dylibloader_wrapper_xlib)(Display *);
+int (*XConfigureWindow_dylibloader_wrapper_xlib)(Display *, Window, unsigned int, XWindowChanges *);
+int (*XConnectionNumber_dylibloader_wrapper_xlib)(Display *);
+int (*XConvertSelection_dylibloader_wrapper_xlib)(Display *, Atom, Atom, Atom, Window, Time);
+int (*XCopyArea_dylibloader_wrapper_xlib)(Display *, Drawable, Drawable, GC, int, int, unsigned int, unsigned int, int, int);
+int (*XCopyGC_dylibloader_wrapper_xlib)(Display *, GC, unsigned long, GC);
+int (*XCopyPlane_dylibloader_wrapper_xlib)(Display *, Drawable, Drawable, GC, int, int, unsigned int, unsigned int, int, int, unsigned long);
+int (*XDefaultDepth_dylibloader_wrapper_xlib)(Display *, int);
+int (*XDefaultDepthOfScreen_dylibloader_wrapper_xlib)(Screen *);
+int (*XDefaultScreen_dylibloader_wrapper_xlib)(Display *);
+int (*XDefineCursor_dylibloader_wrapper_xlib)(Display *, Window, Cursor);
+int (*XDeleteProperty_dylibloader_wrapper_xlib)(Display *, Window, Atom);
+int (*XDestroyWindow_dylibloader_wrapper_xlib)(Display *, Window);
+int (*XDestroySubwindows_dylibloader_wrapper_xlib)(Display *, Window);
+int (*XDoesBackingStore_dylibloader_wrapper_xlib)(Screen *);
+int (*XDoesSaveUnders_dylibloader_wrapper_xlib)(Screen *);
+int (*XDisableAccessControl_dylibloader_wrapper_xlib)(Display *);
+int (*XDisplayCells_dylibloader_wrapper_xlib)(Display *, int);
+int (*XDisplayHeight_dylibloader_wrapper_xlib)(Display *, int);
+int (*XDisplayHeightMM_dylibloader_wrapper_xlib)(Display *, int);
+int (*XDisplayKeycodes_dylibloader_wrapper_xlib)(Display *, int *, int *);
+int (*XDisplayPlanes_dylibloader_wrapper_xlib)(Display *, int);
+int (*XDisplayWidth_dylibloader_wrapper_xlib)(Display *, int);
+int (*XDisplayWidthMM_dylibloader_wrapper_xlib)(Display *, int);
+int (*XDrawArc_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, unsigned int, unsigned int, int, int);
+int (*XDrawArcs_dylibloader_wrapper_xlib)(Display *, Drawable, GC, XArc *, int);
+int (*XDrawImageString_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, const char *, int);
+int (*XDrawImageString16_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, const XChar2b *, int);
+int (*XDrawLine_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, int, int);
+int (*XDrawLines_dylibloader_wrapper_xlib)(Display *, Drawable, GC, XPoint *, int, int);
+int (*XDrawPoint_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int);
+int (*XDrawPoints_dylibloader_wrapper_xlib)(Display *, Drawable, GC, XPoint *, int, int);
+int (*XDrawRectangle_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, unsigned int, unsigned int);
+int (*XDrawRectangles_dylibloader_wrapper_xlib)(Display *, Drawable, GC, XRectangle *, int);
+int (*XDrawSegments_dylibloader_wrapper_xlib)(Display *, Drawable, GC, XSegment *, int);
+int (*XDrawString_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, const char *, int);
+int (*XDrawString16_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, const XChar2b *, int);
+int (*XDrawText_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, XTextItem *, int);
+int (*XDrawText16_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, XTextItem16 *, int);
+int (*XEnableAccessControl_dylibloader_wrapper_xlib)(Display *);
+int (*XEventsQueued_dylibloader_wrapper_xlib)(Display *, int);
+int (*XFetchName_dylibloader_wrapper_xlib)(Display *, Window, char **);
+int (*XFillArc_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, unsigned int, unsigned int, int, int);
+int (*XFillArcs_dylibloader_wrapper_xlib)(Display *, Drawable, GC, XArc *, int);
+int (*XFillPolygon_dylibloader_wrapper_xlib)(Display *, Drawable, GC, XPoint *, int, int, int);
+int (*XFillRectangle_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, unsigned int, unsigned int);
+int (*XFillRectangles_dylibloader_wrapper_xlib)(Display *, Drawable, GC, XRectangle *, int);
+int (*XFlush_dylibloader_wrapper_xlib)(Display *);
+int (*XForceScreenSaver_dylibloader_wrapper_xlib)(Display *, int);
+int (*XFree_dylibloader_wrapper_xlib)(void *);
+int (*XFreeColormap_dylibloader_wrapper_xlib)(Display *, Colormap);
+int (*XFreeColors_dylibloader_wrapper_xlib)(Display *, Colormap, unsigned long *, int, unsigned long);
+int (*XFreeCursor_dylibloader_wrapper_xlib)(Display *, Cursor);
+int (*XFreeExtensionList_dylibloader_wrapper_xlib)(char **);
+int (*XFreeFont_dylibloader_wrapper_xlib)(Display *, XFontStruct *);
+int (*XFreeFontInfo_dylibloader_wrapper_xlib)(char **, XFontStruct *, int);
+int (*XFreeFontNames_dylibloader_wrapper_xlib)(char **);
+int (*XFreeFontPath_dylibloader_wrapper_xlib)(char **);
+int (*XFreeGC_dylibloader_wrapper_xlib)(Display *, GC);
+int (*XFreeModifiermap_dylibloader_wrapper_xlib)(XModifierKeymap *);
+int (*XFreePixmap_dylibloader_wrapper_xlib)(Display *, Pixmap);
+int (*XGeometry_dylibloader_wrapper_xlib)(Display *, int, const char *, const char *, unsigned int, unsigned int, unsigned int, int, int, int *, int *, int *, int *);
+int (*XGetErrorDatabaseText_dylibloader_wrapper_xlib)(Display *, const char *, const char *, const char *, char *, int);
+int (*XGetErrorText_dylibloader_wrapper_xlib)(Display *, int, char *, int);
+int (*XGetFontProperty_dylibloader_wrapper_xlib)(XFontStruct *, Atom, unsigned long *);
+int (*XGetGCValues_dylibloader_wrapper_xlib)(Display *, GC, unsigned long, XGCValues *);
+int (*XGetGeometry_dylibloader_wrapper_xlib)(Display *, Drawable, Window *, int *, int *, unsigned int *, unsigned int *, unsigned int *, unsigned int *);
+int (*XGetIconName_dylibloader_wrapper_xlib)(Display *, Window, char **);
+int (*XGetInputFocus_dylibloader_wrapper_xlib)(Display *, Window *, int *);
+int (*XGetKeyboardControl_dylibloader_wrapper_xlib)(Display *, XKeyboardState *);
+int (*XGetPointerControl_dylibloader_wrapper_xlib)(Display *, int *, int *, int *);
+int (*XGetPointerMapping_dylibloader_wrapper_xlib)(Display *, unsigned char *, int);
+int (*XGetScreenSaver_dylibloader_wrapper_xlib)(Display *, int *, int *, int *, int *);
+int (*XGetTransientForHint_dylibloader_wrapper_xlib)(Display *, Window, Window *);
+int (*XGetWindowProperty_dylibloader_wrapper_xlib)(Display *, Window, Atom, long, long, int, Atom, Atom *, int *, unsigned long *, unsigned long *, unsigned char **);
+int (*XGetWindowAttributes_dylibloader_wrapper_xlib)(Display *, Window, XWindowAttributes *);
+int (*XGrabButton_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, Window, int, unsigned int, int, int, Window, Cursor);
+int (*XGrabKey_dylibloader_wrapper_xlib)(Display *, int, unsigned int, Window, int, int, int);
+int (*XGrabKeyboard_dylibloader_wrapper_xlib)(Display *, Window, int, int, int, Time);
+int (*XGrabPointer_dylibloader_wrapper_xlib)(Display *, Window, int, unsigned int, int, int, Window, Cursor, Time);
+int (*XGrabServer_dylibloader_wrapper_xlib)(Display *);
+int (*XHeightMMOfScreen_dylibloader_wrapper_xlib)(Screen *);
+int (*XHeightOfScreen_dylibloader_wrapper_xlib)(Screen *);
+int (*XIfEvent_dylibloader_wrapper_xlib)(Display *, XEvent *, int (*)(Display *, XEvent *, XPointer), XPointer);
+int (*XImageByteOrder_dylibloader_wrapper_xlib)(Display *);
+int (*XInstallColormap_dylibloader_wrapper_xlib)(Display *, Colormap);
+KeyCode (*XKeysymToKeycode_dylibloader_wrapper_xlib)(Display *, KeySym);
+int (*XKillClient_dylibloader_wrapper_xlib)(Display *, XID);
+int (*XLookupColor_dylibloader_wrapper_xlib)(Display *, Colormap, const char *, XColor *, XColor *);
+int (*XLowerWindow_dylibloader_wrapper_xlib)(Display *, Window);
+int (*XMapRaised_dylibloader_wrapper_xlib)(Display *, Window);
+int (*XMapSubwindows_dylibloader_wrapper_xlib)(Display *, Window);
+int (*XMapWindow_dylibloader_wrapper_xlib)(Display *, Window);
+int (*XMaskEvent_dylibloader_wrapper_xlib)(Display *, long, XEvent *);
+int (*XMaxCmapsOfScreen_dylibloader_wrapper_xlib)(Screen *);
+int (*XMinCmapsOfScreen_dylibloader_wrapper_xlib)(Screen *);
+int (*XMoveResizeWindow_dylibloader_wrapper_xlib)(Display *, Window, int, int, unsigned int, unsigned int);
+int (*XMoveWindow_dylibloader_wrapper_xlib)(Display *, Window, int, int);
+int (*XNextEvent_dylibloader_wrapper_xlib)(Display *, XEvent *);
+int (*XNoOp_dylibloader_wrapper_xlib)(Display *);
+int (*XParseColor_dylibloader_wrapper_xlib)(Display *, Colormap, const char *, XColor *);
+int (*XParseGeometry_dylibloader_wrapper_xlib)(const char *, int *, int *, unsigned int *, unsigned int *);
+int (*XPeekEvent_dylibloader_wrapper_xlib)(Display *, XEvent *);
+int (*XPeekIfEvent_dylibloader_wrapper_xlib)(Display *, XEvent *, int (*)(Display *, XEvent *, XPointer), XPointer);
+int (*XPending_dylibloader_wrapper_xlib)(Display *);
+int (*XPlanesOfScreen_dylibloader_wrapper_xlib)(Screen *);
+int (*XProtocolRevision_dylibloader_wrapper_xlib)(Display *);
+int (*XProtocolVersion_dylibloader_wrapper_xlib)(Display *);
+int (*XPutBackEvent_dylibloader_wrapper_xlib)(Display *, XEvent *);
+int (*XPutImage_dylibloader_wrapper_xlib)(Display *, Drawable, GC, XImage *, int, int, int, int, unsigned int, unsigned int);
+int (*XQLength_dylibloader_wrapper_xlib)(Display *);
+int (*XQueryBestCursor_dylibloader_wrapper_xlib)(Display *, Drawable, unsigned int, unsigned int, unsigned int *, unsigned int *);
+int (*XQueryBestSize_dylibloader_wrapper_xlib)(Display *, int, Drawable, unsigned int, unsigned int, unsigned int *, unsigned int *);
+int (*XQueryBestStipple_dylibloader_wrapper_xlib)(Display *, Drawable, unsigned int, unsigned int, unsigned int *, unsigned int *);
+int (*XQueryBestTile_dylibloader_wrapper_xlib)(Display *, Drawable, unsigned int, unsigned int, unsigned int *, unsigned int *);
+int (*XQueryColor_dylibloader_wrapper_xlib)(Display *, Colormap, XColor *);
+int (*XQueryColors_dylibloader_wrapper_xlib)(Display *, Colormap, XColor *, int);
+int (*XQueryExtension_dylibloader_wrapper_xlib)(Display *, const char *, int *, int *, int *);
+int (*XQueryKeymap_dylibloader_wrapper_xlib)(Display *, char [32]);
+int (*XQueryPointer_dylibloader_wrapper_xlib)(Display *, Window, Window *, Window *, int *, int *, int *, int *, unsigned int *);
+int (*XQueryTextExtents_dylibloader_wrapper_xlib)(Display *, XID, const char *, int, int *, int *, int *, XCharStruct *);
+int (*XQueryTextExtents16_dylibloader_wrapper_xlib)(Display *, XID, const XChar2b *, int, int *, int *, int *, XCharStruct *);
+int (*XQueryTree_dylibloader_wrapper_xlib)(Display *, Window, Window *, Window *, Window **, unsigned int *);
+int (*XRaiseWindow_dylibloader_wrapper_xlib)(Display *, Window);
+int (*XReadBitmapFile_dylibloader_wrapper_xlib)(Display *, Drawable, const char *, unsigned int *, unsigned int *, Pixmap *, int *, int *);
+int (*XReadBitmapFileData_dylibloader_wrapper_xlib)(const char *, unsigned int *, unsigned int *, unsigned char **, int *, int *);
+int (*XRebindKeysym_dylibloader_wrapper_xlib)(Display *, KeySym, KeySym *, int, const unsigned char *, int);
+int (*XRecolorCursor_dylibloader_wrapper_xlib)(Display *, Cursor, XColor *, XColor *);
+int (*XRefreshKeyboardMapping_dylibloader_wrapper_xlib)(XMappingEvent *);
+int (*XRemoveFromSaveSet_dylibloader_wrapper_xlib)(Display *, Window);
+int (*XRemoveHost_dylibloader_wrapper_xlib)(Display *, XHostAddress *);
+int (*XRemoveHosts_dylibloader_wrapper_xlib)(Display *, XHostAddress *, int);
+int (*XReparentWindow_dylibloader_wrapper_xlib)(Display *, Window, Window, int, int);
+int (*XResetScreenSaver_dylibloader_wrapper_xlib)(Display *);
+int (*XResizeWindow_dylibloader_wrapper_xlib)(Display *, Window, unsigned int, unsigned int);
+int (*XRestackWindows_dylibloader_wrapper_xlib)(Display *, Window *, int);
+int (*XRotateBuffers_dylibloader_wrapper_xlib)(Display *, int);
+int (*XRotateWindowProperties_dylibloader_wrapper_xlib)(Display *, Window, Atom *, int, int);
+int (*XScreenCount_dylibloader_wrapper_xlib)(Display *);
+int (*XSelectInput_dylibloader_wrapper_xlib)(Display *, Window, long);
+int (*XSendEvent_dylibloader_wrapper_xlib)(Display *, Window, int, long, XEvent *);
+int (*XSetAccessControl_dylibloader_wrapper_xlib)(Display *, int);
+int (*XSetArcMode_dylibloader_wrapper_xlib)(Display *, GC, int);
+int (*XSetBackground_dylibloader_wrapper_xlib)(Display *, GC, unsigned long);
+int (*XSetClipMask_dylibloader_wrapper_xlib)(Display *, GC, Pixmap);
+int (*XSetClipOrigin_dylibloader_wrapper_xlib)(Display *, GC, int, int);
+int (*XSetClipRectangles_dylibloader_wrapper_xlib)(Display *, GC, int, int, XRectangle *, int, int);
+int (*XSetCloseDownMode_dylibloader_wrapper_xlib)(Display *, int);
+int (*XSetCommand_dylibloader_wrapper_xlib)(Display *, Window, char **, int);
+int (*XSetDashes_dylibloader_wrapper_xlib)(Display *, GC, int, const char *, int);
+int (*XSetFillRule_dylibloader_wrapper_xlib)(Display *, GC, int);
+int (*XSetFillStyle_dylibloader_wrapper_xlib)(Display *, GC, int);
+int (*XSetFont_dylibloader_wrapper_xlib)(Display *, GC, Font);
+int (*XSetFontPath_dylibloader_wrapper_xlib)(Display *, char **, int);
+int (*XSetForeground_dylibloader_wrapper_xlib)(Display *, GC, unsigned long);
+int (*XSetFunction_dylibloader_wrapper_xlib)(Display *, GC, int);
+int (*XSetGraphicsExposures_dylibloader_wrapper_xlib)(Display *, GC, int);
+int (*XSetIconName_dylibloader_wrapper_xlib)(Display *, Window, const char *);
+int (*XSetInputFocus_dylibloader_wrapper_xlib)(Display *, Window, int, Time);
+int (*XSetLineAttributes_dylibloader_wrapper_xlib)(Display *, GC, unsigned int, int, int, int);
+int (*XSetModifierMapping_dylibloader_wrapper_xlib)(Display *, XModifierKeymap *);
+int (*XSetPlaneMask_dylibloader_wrapper_xlib)(Display *, GC, unsigned long);
+int (*XSetPointerMapping_dylibloader_wrapper_xlib)(Display *, const unsigned char *, int);
+int (*XSetScreenSaver_dylibloader_wrapper_xlib)(Display *, int, int, int, int);
+int (*XSetSelectionOwner_dylibloader_wrapper_xlib)(Display *, Atom, Window, Time);
+int (*XSetState_dylibloader_wrapper_xlib)(Display *, GC, unsigned long, unsigned long, int, unsigned long);
+int (*XSetStipple_dylibloader_wrapper_xlib)(Display *, GC, Pixmap);
+int (*XSetSubwindowMode_dylibloader_wrapper_xlib)(Display *, GC, int);
+int (*XSetTSOrigin_dylibloader_wrapper_xlib)(Display *, GC, int, int);
+int (*XSetTile_dylibloader_wrapper_xlib)(Display *, GC, Pixmap);
+int (*XSetWindowBackground_dylibloader_wrapper_xlib)(Display *, Window, unsigned long);
+int (*XSetWindowBackgroundPixmap_dylibloader_wrapper_xlib)(Display *, Window, Pixmap);
+int (*XSetWindowBorder_dylibloader_wrapper_xlib)(Display *, Window, unsigned long);
+int (*XSetWindowBorderPixmap_dylibloader_wrapper_xlib)(Display *, Window, Pixmap);
+int (*XSetWindowBorderWidth_dylibloader_wrapper_xlib)(Display *, Window, unsigned int);
+int (*XSetWindowColormap_dylibloader_wrapper_xlib)(Display *, Window, Colormap);
+int (*XStoreBuffer_dylibloader_wrapper_xlib)(Display *, const char *, int, int);
+int (*XStoreBytes_dylibloader_wrapper_xlib)(Display *, const char *, int);
+int (*XStoreColor_dylibloader_wrapper_xlib)(Display *, Colormap, XColor *);
+int (*XStoreColors_dylibloader_wrapper_xlib)(Display *, Colormap, XColor *, int);
+int (*XStoreName_dylibloader_wrapper_xlib)(Display *, Window, const char *);
+int (*XStoreNamedColor_dylibloader_wrapper_xlib)(Display *, Colormap, const char *, unsigned long, int);
+int (*XSync_dylibloader_wrapper_xlib)(Display *, int);
+int (*XTextExtents_dylibloader_wrapper_xlib)(XFontStruct *, const char *, int, int *, int *, int *, XCharStruct *);
+int (*XTextExtents16_dylibloader_wrapper_xlib)(XFontStruct *, const XChar2b *, int, int *, int *, int *, XCharStruct *);
+int (*XTextWidth_dylibloader_wrapper_xlib)(XFontStruct *, const char *, int);
+int (*XTextWidth16_dylibloader_wrapper_xlib)(XFontStruct *, const XChar2b *, int);
+int (*XTranslateCoordinates_dylibloader_wrapper_xlib)(Display *, Window, Window, int, int, int *, int *, Window *);
+int (*XUndefineCursor_dylibloader_wrapper_xlib)(Display *, Window);
+int (*XUngrabButton_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, Window);
+int (*XUngrabKey_dylibloader_wrapper_xlib)(Display *, int, unsigned int, Window);
+int (*XUngrabKeyboard_dylibloader_wrapper_xlib)(Display *, Time);
+int (*XUngrabPointer_dylibloader_wrapper_xlib)(Display *, Time);
+int (*XUngrabServer_dylibloader_wrapper_xlib)(Display *);
+int (*XUninstallColormap_dylibloader_wrapper_xlib)(Display *, Colormap);
+int (*XUnloadFont_dylibloader_wrapper_xlib)(Display *, Font);
+int (*XUnmapSubwindows_dylibloader_wrapper_xlib)(Display *, Window);
+int (*XUnmapWindow_dylibloader_wrapper_xlib)(Display *, Window);
+int (*XVendorRelease_dylibloader_wrapper_xlib)(Display *);
+int (*XWarpPointer_dylibloader_wrapper_xlib)(Display *, Window, Window, int, int, unsigned int, unsigned int, int, int);
+int (*XWidthMMOfScreen_dylibloader_wrapper_xlib)(Screen *);
+int (*XWidthOfScreen_dylibloader_wrapper_xlib)(Screen *);
+int (*XWindowEvent_dylibloader_wrapper_xlib)(Display *, Window, long, XEvent *);
+int (*XWriteBitmapFile_dylibloader_wrapper_xlib)(Display *, const char *, Pixmap, unsigned int, unsigned int, int, int);
+int (*XSupportsLocale_dylibloader_wrapper_xlib)(void);
+char *(*XSetLocaleModifiers_dylibloader_wrapper_xlib)(const char *);
+XOM (*XOpenOM_dylibloader_wrapper_xlib)(Display *, struct _XrmHashBucketRec *, const char *, const char *);
+int (*XCloseOM_dylibloader_wrapper_xlib)(XOM);
+char *(*XSetOMValues_dylibloader_wrapper_xlib)(XOM, ...);
+char *(*XGetOMValues_dylibloader_wrapper_xlib)(XOM, ...);
+Display *(*XDisplayOfOM_dylibloader_wrapper_xlib)(XOM);
+char *(*XLocaleOfOM_dylibloader_wrapper_xlib)(XOM);
+XOC (*XCreateOC_dylibloader_wrapper_xlib)(XOM, ...);
+void (*XDestroyOC_dylibloader_wrapper_xlib)(XOC);
+XOM (*XOMOfOC_dylibloader_wrapper_xlib)(XOC);
+char *(*XSetOCValues_dylibloader_wrapper_xlib)(XOC, ...);
+char *(*XGetOCValues_dylibloader_wrapper_xlib)(XOC, ...);
+XFontSet (*XCreateFontSet_dylibloader_wrapper_xlib)(Display *, const char *, char ***, int *, char **);
+void (*XFreeFontSet_dylibloader_wrapper_xlib)(Display *, XFontSet);
+int (*XFontsOfFontSet_dylibloader_wrapper_xlib)(XFontSet, XFontStruct ***, char ***);
+char *(*XBaseFontNameListOfFontSet_dylibloader_wrapper_xlib)(XFontSet);
+char *(*XLocaleOfFontSet_dylibloader_wrapper_xlib)(XFontSet);
+int (*XContextDependentDrawing_dylibloader_wrapper_xlib)(XFontSet);
+int (*XDirectionalDependentDrawing_dylibloader_wrapper_xlib)(XFontSet);
+int (*XContextualDrawing_dylibloader_wrapper_xlib)(XFontSet);
+XFontSetExtents *(*XExtentsOfFontSet_dylibloader_wrapper_xlib)(XFontSet);
+int (*XmbTextEscapement_dylibloader_wrapper_xlib)(XFontSet, const char *, int);
+int (*XwcTextEscapement_dylibloader_wrapper_xlib)(XFontSet, const wchar_t *, int);
+int (*Xutf8TextEscapement_dylibloader_wrapper_xlib)(XFontSet, const char *, int);
+int (*XmbTextExtents_dylibloader_wrapper_xlib)(XFontSet, const char *, int, XRectangle *, XRectangle *);
+int (*XwcTextExtents_dylibloader_wrapper_xlib)(XFontSet, const wchar_t *, int, XRectangle *, XRectangle *);
+int (*Xutf8TextExtents_dylibloader_wrapper_xlib)(XFontSet, const char *, int, XRectangle *, XRectangle *);
+int (*XmbTextPerCharExtents_dylibloader_wrapper_xlib)(XFontSet, const char *, int, XRectangle *, XRectangle *, int, int *, XRectangle *, XRectangle *);
+int (*XwcTextPerCharExtents_dylibloader_wrapper_xlib)(XFontSet, const wchar_t *, int, XRectangle *, XRectangle *, int, int *, XRectangle *, XRectangle *);
+int (*Xutf8TextPerCharExtents_dylibloader_wrapper_xlib)(XFontSet, const char *, int, XRectangle *, XRectangle *, int, int *, XRectangle *, XRectangle *);
+void (*XmbDrawText_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, XmbTextItem *, int);
+void (*XwcDrawText_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, XwcTextItem *, int);
+void (*Xutf8DrawText_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, XmbTextItem *, int);
+void (*XmbDrawString_dylibloader_wrapper_xlib)(Display *, Drawable, XFontSet, GC, int, int, const char *, int);
+void (*XwcDrawString_dylibloader_wrapper_xlib)(Display *, Drawable, XFontSet, GC, int, int, const wchar_t *, int);
+void (*Xutf8DrawString_dylibloader_wrapper_xlib)(Display *, Drawable, XFontSet, GC, int, int, const char *, int);
+void (*XmbDrawImageString_dylibloader_wrapper_xlib)(Display *, Drawable, XFontSet, GC, int, int, const char *, int);
+void (*XwcDrawImageString_dylibloader_wrapper_xlib)(Display *, Drawable, XFontSet, GC, int, int, const wchar_t *, int);
+void (*Xutf8DrawImageString_dylibloader_wrapper_xlib)(Display *, Drawable, XFontSet, GC, int, int, const char *, int);
+XIM (*XOpenIM_dylibloader_wrapper_xlib)(Display *, struct _XrmHashBucketRec *, char *, char *);
+int (*XCloseIM_dylibloader_wrapper_xlib)(XIM);
+char *(*XGetIMValues_dylibloader_wrapper_xlib)(XIM, ...);
+char *(*XSetIMValues_dylibloader_wrapper_xlib)(XIM, ...);
+Display *(*XDisplayOfIM_dylibloader_wrapper_xlib)(XIM);
+char *(*XLocaleOfIM_dylibloader_wrapper_xlib)(XIM);
+XIC (*XCreateIC_dylibloader_wrapper_xlib)(XIM, ...);
+void (*XDestroyIC_dylibloader_wrapper_xlib)(XIC);
+void (*XSetICFocus_dylibloader_wrapper_xlib)(XIC);
+void (*XUnsetICFocus_dylibloader_wrapper_xlib)(XIC);
+wchar_t *(*XwcResetIC_dylibloader_wrapper_xlib)(XIC);
+char *(*XmbResetIC_dylibloader_wrapper_xlib)(XIC);
+char *(*Xutf8ResetIC_dylibloader_wrapper_xlib)(XIC);
+char *(*XSetICValues_dylibloader_wrapper_xlib)(XIC, ...);
+char *(*XGetICValues_dylibloader_wrapper_xlib)(XIC, ...);
+XIM (*XIMOfIC_dylibloader_wrapper_xlib)(XIC);
+int (*XFilterEvent_dylibloader_wrapper_xlib)(XEvent *, Window);
+int (*XmbLookupString_dylibloader_wrapper_xlib)(XIC, XKeyPressedEvent *, char *, int, KeySym *, int *);
+int (*XwcLookupString_dylibloader_wrapper_xlib)(XIC, XKeyPressedEvent *, wchar_t *, int, KeySym *, int *);
+int (*Xutf8LookupString_dylibloader_wrapper_xlib)(XIC, XKeyPressedEvent *, char *, int, KeySym *, int *);
+XVaNestedList (*XVaCreateNestedList_dylibloader_wrapper_xlib)(int, ...);
+int (*XRegisterIMInstantiateCallback_dylibloader_wrapper_xlib)(Display *, struct _XrmHashBucketRec *, char *, char *, XIDProc, XPointer);
+int (*XUnregisterIMInstantiateCallback_dylibloader_wrapper_xlib)(Display *, struct _XrmHashBucketRec *, char *, char *, XIDProc, XPointer);
+int (*XInternalConnectionNumbers_dylibloader_wrapper_xlib)(Display *, int **, int *);
+void (*XProcessInternalConnection_dylibloader_wrapper_xlib)(Display *, int);
+int (*XAddConnectionWatch_dylibloader_wrapper_xlib)(Display *, XConnectionWatchProc, XPointer);
+void (*XRemoveConnectionWatch_dylibloader_wrapper_xlib)(Display *, XConnectionWatchProc, XPointer);
+void (*XSetAuthorization_dylibloader_wrapper_xlib)(char *, int, char *, int);
+int (*_Xmbtowc_dylibloader_wrapper_xlib)(wchar_t *, char *, int);
+int (*_Xwctomb_dylibloader_wrapper_xlib)(char *, wchar_t);
+int (*XGetEventData_dylibloader_wrapper_xlib)(Display *, XGenericEventCookie *);
+void (*XFreeEventData_dylibloader_wrapper_xlib)(Display *, XGenericEventCookie *);
+int (*XFreeThreads_dylibloader_wrapper_xlib)(void);
+XClassHint *(*XAllocClassHint_dylibloader_wrapper_xlib)(void);
+XIconSize *(*XAllocIconSize_dylibloader_wrapper_xlib)(void);
+XSizeHints *(*XAllocSizeHints_dylibloader_wrapper_xlib)(void);
+XStandardColormap *(*XAllocStandardColormap_dylibloader_wrapper_xlib)(void);
+XWMHints *(*XAllocWMHints_dylibloader_wrapper_xlib)(void);
+int (*XClipBox_dylibloader_wrapper_xlib)(Region, XRectangle *);
+Region (*XCreateRegion_dylibloader_wrapper_xlib)(void);
+const char *(*XDefaultString_dylibloader_wrapper_xlib)(void);
+int (*XDeleteContext_dylibloader_wrapper_xlib)(Display *, XID, XContext);
+int (*XDestroyRegion_dylibloader_wrapper_xlib)(Region);
+int (*XEmptyRegion_dylibloader_wrapper_xlib)(Region);
+int (*XEqualRegion_dylibloader_wrapper_xlib)(Region, Region);
+int (*XFindContext_dylibloader_wrapper_xlib)(Display *, XID, XContext, XPointer *);
+int (*XGetClassHint_dylibloader_wrapper_xlib)(Display *, Window, XClassHint *);
+int (*XGetIconSizes_dylibloader_wrapper_xlib)(Display *, Window, XIconSize **, int *);
+int (*XGetNormalHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *);
+int (*XGetRGBColormaps_dylibloader_wrapper_xlib)(Display *, Window, XStandardColormap **, int *, Atom);
+int (*XGetSizeHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *, Atom);
+int (*XGetStandardColormap_dylibloader_wrapper_xlib)(Display *, Window, XStandardColormap *, Atom);
+int (*XGetTextProperty_dylibloader_wrapper_xlib)(Display *, Window, XTextProperty *, Atom);
+XVisualInfo *(*XGetVisualInfo_dylibloader_wrapper_xlib)(Display *, long, XVisualInfo *, int *);
+int (*XGetWMClientMachine_dylibloader_wrapper_xlib)(Display *, Window, XTextProperty *);
+XWMHints *(*XGetWMHints_dylibloader_wrapper_xlib)(Display *, Window);
+int (*XGetWMIconName_dylibloader_wrapper_xlib)(Display *, Window, XTextProperty *);
+int (*XGetWMName_dylibloader_wrapper_xlib)(Display *, Window, XTextProperty *);
+int (*XGetWMNormalHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *, long *);
+int (*XGetWMSizeHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *, long *, Atom);
+int (*XGetZoomHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *);
+int (*XIntersectRegion_dylibloader_wrapper_xlib)(Region, Region, Region);
+void (*XConvertCase_dylibloader_wrapper_xlib)(KeySym, KeySym *, KeySym *);
+int (*XLookupString_dylibloader_wrapper_xlib)(XKeyEvent *, char *, int, KeySym *, XComposeStatus *);
+int (*XMatchVisualInfo_dylibloader_wrapper_xlib)(Display *, int, int, int, XVisualInfo *);
+int (*XOffsetRegion_dylibloader_wrapper_xlib)(Region, int, int);
+int (*XPointInRegion_dylibloader_wrapper_xlib)(Region, int, int);
+Region (*XPolygonRegion_dylibloader_wrapper_xlib)(XPoint *, int, int);
+int (*XRectInRegion_dylibloader_wrapper_xlib)(Region, int, int, unsigned int, unsigned int);
+int (*XSaveContext_dylibloader_wrapper_xlib)(Display *, XID, XContext, const char *);
+int (*XSetClassHint_dylibloader_wrapper_xlib)(Display *, Window, XClassHint *);
+int (*XSetIconSizes_dylibloader_wrapper_xlib)(Display *, Window, XIconSize *, int);
+int (*XSetNormalHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *);
+void (*XSetRGBColormaps_dylibloader_wrapper_xlib)(Display *, Window, XStandardColormap *, int, Atom);
+int (*XSetSizeHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *, Atom);
+int (*XSetStandardProperties_dylibloader_wrapper_xlib)(Display *, Window, const char *, const char *, Pixmap, char **, int, XSizeHints *);
+void (*XSetTextProperty_dylibloader_wrapper_xlib)(Display *, Window, XTextProperty *, Atom);
+void (*XSetWMClientMachine_dylibloader_wrapper_xlib)(Display *, Window, XTextProperty *);
+int (*XSetWMHints_dylibloader_wrapper_xlib)(Display *, Window, XWMHints *);
+void (*XSetWMIconName_dylibloader_wrapper_xlib)(Display *, Window, XTextProperty *);
+void (*XSetWMName_dylibloader_wrapper_xlib)(Display *, Window, XTextProperty *);
+void (*XSetWMNormalHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *);
+void (*XSetWMProperties_dylibloader_wrapper_xlib)(Display *, Window, XTextProperty *, XTextProperty *, char **, int, XSizeHints *, XWMHints *, XClassHint *);
+void (*XmbSetWMProperties_dylibloader_wrapper_xlib)(Display *, Window, const char *, const char *, char **, int, XSizeHints *, XWMHints *, XClassHint *);
+void (*Xutf8SetWMProperties_dylibloader_wrapper_xlib)(Display *, Window, const char *, const char *, char **, int, XSizeHints *, XWMHints *, XClassHint *);
+void (*XSetWMSizeHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *, Atom);
+int (*XSetRegion_dylibloader_wrapper_xlib)(Display *, GC, Region);
+void (*XSetStandardColormap_dylibloader_wrapper_xlib)(Display *, Window, XStandardColormap *, Atom);
+int (*XSetZoomHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *);
+int (*XShrinkRegion_dylibloader_wrapper_xlib)(Region, int, int);
+int (*XStringListToTextProperty_dylibloader_wrapper_xlib)(char **, int, XTextProperty *);
+int (*XSubtractRegion_dylibloader_wrapper_xlib)(Region, Region, Region);
+int (*XmbTextListToTextProperty_dylibloader_wrapper_xlib)(Display *, char **, int, XICCEncodingStyle, XTextProperty *);
+int (*XwcTextListToTextProperty_dylibloader_wrapper_xlib)(Display *, wchar_t **, int, XICCEncodingStyle, XTextProperty *);
+int (*Xutf8TextListToTextProperty_dylibloader_wrapper_xlib)(Display *, char **, int, XICCEncodingStyle, XTextProperty *);
+void (*XwcFreeStringList_dylibloader_wrapper_xlib)(wchar_t **);
+int (*XTextPropertyToStringList_dylibloader_wrapper_xlib)(XTextProperty *, char ***, int *);
+int (*XmbTextPropertyToTextList_dylibloader_wrapper_xlib)(Display *, const XTextProperty *, char ***, int *);
+int (*XwcTextPropertyToTextList_dylibloader_wrapper_xlib)(Display *, const XTextProperty *, wchar_t ***, int *);
+int (*Xutf8TextPropertyToTextList_dylibloader_wrapper_xlib)(Display *, const XTextProperty *, char ***, int *);
+int (*XUnionRectWithRegion_dylibloader_wrapper_xlib)(XRectangle *, Region, Region);
+int (*XUnionRegion_dylibloader_wrapper_xlib)(Region, Region, Region);
+int (*XWMGeometry_dylibloader_wrapper_xlib)(Display *, int, const char *, const char *, unsigned int, XSizeHints *, int *, int *, int *, int *, int *);
+int (*XXorRegion_dylibloader_wrapper_xlib)(Region, Region, Region);
+int (*XkbIgnoreExtension_dylibloader_wrapper_xlib)(int);
+Display *(*XkbOpenDisplay_dylibloader_wrapper_xlib)(char *, int *, int *, int *, int *, int *);
+int (*XkbQueryExtension_dylibloader_wrapper_xlib)(Display *, int *, int *, int *, int *, int *);
+int (*XkbUseExtension_dylibloader_wrapper_xlib)(Display *, int *, int *);
+int (*XkbLibraryVersion_dylibloader_wrapper_xlib)(int *, int *);
+unsigned int (*XkbSetXlibControls_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int);
+unsigned int (*XkbGetXlibControls_dylibloader_wrapper_xlib)(Display *);
+unsigned int (*XkbXlibControlsImplemented_dylibloader_wrapper_xlib)(void);
+void (*XkbSetAtomFuncs_dylibloader_wrapper_xlib)(XkbInternAtomFunc, XkbGetAtomNameFunc);
+KeySym (*XkbKeycodeToKeysym_dylibloader_wrapper_xlib)(Display *, KeyCode, int, int);
+unsigned int (*XkbKeysymToModifiers_dylibloader_wrapper_xlib)(Display *, KeySym);
+int (*XkbLookupKeySym_dylibloader_wrapper_xlib)(Display *, KeyCode, unsigned int, unsigned int *, KeySym *);
+int (*XkbLookupKeyBinding_dylibloader_wrapper_xlib)(Display *, KeySym, unsigned int, char *, int, int *);
+int (*XkbTranslateKeyCode_dylibloader_wrapper_xlib)(XkbDescPtr, KeyCode, unsigned int, unsigned int *, KeySym *);
+int (*XkbTranslateKeySym_dylibloader_wrapper_xlib)(Display *, KeySym *, unsigned int, char *, int, int *);
+int (*XkbSetAutoRepeatRate_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int);
+int (*XkbGetAutoRepeatRate_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int *, unsigned int *);
+int (*XkbChangeEnabledControls_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int);
+int (*XkbDeviceBell_dylibloader_wrapper_xlib)(Display *, Window, int, int, int, int, Atom);
+int (*XkbForceDeviceBell_dylibloader_wrapper_xlib)(Display *, int, int, int, int);
+int (*XkbDeviceBellEvent_dylibloader_wrapper_xlib)(Display *, Window, int, int, int, int, Atom);
+int (*XkbBell_dylibloader_wrapper_xlib)(Display *, Window, int, Atom);
+int (*XkbForceBell_dylibloader_wrapper_xlib)(Display *, int);
+int (*XkbBellEvent_dylibloader_wrapper_xlib)(Display *, Window, int, Atom);
+int (*XkbSelectEvents_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int);
+int (*XkbSelectEventDetails_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned long, unsigned long);
+void (*XkbNoteMapChanges_dylibloader_wrapper_xlib)(XkbMapChangesPtr, XkbMapNotifyEvent *, unsigned int);
+void (*XkbNoteNameChanges_dylibloader_wrapper_xlib)(XkbNameChangesPtr, XkbNamesNotifyEvent *, unsigned int);
+int (*XkbGetIndicatorState_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int *);
+int (*XkbGetIndicatorMap_dylibloader_wrapper_xlib)(Display *, unsigned long, XkbDescPtr);
+int (*XkbSetIndicatorMap_dylibloader_wrapper_xlib)(Display *, unsigned long, XkbDescPtr);
+int (*XkbGetNamedIndicator_dylibloader_wrapper_xlib)(Display *, Atom, int *, int *, XkbIndicatorMapPtr, int *);
+int (*XkbGetNamedDeviceIndicator_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int, Atom, int *, int *, XkbIndicatorMapPtr, int *);
+int (*XkbSetNamedIndicator_dylibloader_wrapper_xlib)(Display *, Atom, int, int, int, XkbIndicatorMapPtr);
+int (*XkbSetNamedDeviceIndicator_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int, Atom, int, int, int, XkbIndicatorMapPtr);
+int (*XkbLockModifiers_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int);
+int (*XkbLatchModifiers_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int);
+int (*XkbLockGroup_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int);
+int (*XkbLatchGroup_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int);
+int (*XkbSetServerInternalMods_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int);
+int (*XkbSetIgnoreLockMods_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int);
+int (*XkbVirtualModsToReal_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, unsigned int *);
+int (*XkbComputeEffectiveMap_dylibloader_wrapper_xlib)(XkbDescPtr, XkbKeyTypePtr, unsigned char *);
+int (*XkbInitCanonicalKeyTypes_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, int);
+XkbDescPtr (*XkbAllocKeyboard_dylibloader_wrapper_xlib)(void);
+void (*XkbFreeKeyboard_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, int);
+int (*XkbAllocClientMap_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, unsigned int);
+int (*XkbAllocServerMap_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, unsigned int);
+void (*XkbFreeClientMap_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, int);
+void (*XkbFreeServerMap_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, int);
+XkbKeyTypePtr (*XkbAddKeyType_dylibloader_wrapper_xlib)(XkbDescPtr, Atom, int, int, int);
+int (*XkbAllocIndicatorMaps_dylibloader_wrapper_xlib)(XkbDescPtr);
+void (*XkbFreeIndicatorMaps_dylibloader_wrapper_xlib)(XkbDescPtr);
+XkbDescPtr (*XkbGetMap_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int);
+int (*XkbGetUpdatedMap_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbDescPtr);
+int (*XkbGetMapChanges_dylibloader_wrapper_xlib)(Display *, XkbDescPtr, XkbMapChangesPtr);
+int (*XkbRefreshKeyboardMapping_dylibloader_wrapper_xlib)(XkbMapNotifyEvent *);
+int (*XkbGetKeyTypes_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, XkbDescPtr);
+int (*XkbGetKeySyms_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, XkbDescPtr);
+int (*XkbGetKeyActions_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, XkbDescPtr);
+int (*XkbGetKeyBehaviors_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, XkbDescPtr);
+int (*XkbGetVirtualMods_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbDescPtr);
+int (*XkbGetKeyExplicitComponents_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, XkbDescPtr);
+int (*XkbGetKeyModifierMap_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, XkbDescPtr);
+int (*XkbGetKeyVirtualModMap_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, XkbDescPtr);
+int (*XkbAllocControls_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int);
+void (*XkbFreeControls_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, int);
+int (*XkbGetControls_dylibloader_wrapper_xlib)(Display *, unsigned long, XkbDescPtr);
+int (*XkbSetControls_dylibloader_wrapper_xlib)(Display *, unsigned long, XkbDescPtr);
+void (*XkbNoteControlsChanges_dylibloader_wrapper_xlib)(XkbControlsChangesPtr, XkbControlsNotifyEvent *, unsigned int);
+int (*XkbAllocCompatMap_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, unsigned int);
+void (*XkbFreeCompatMap_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, int);
+int (*XkbGetCompatMap_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbDescPtr);
+int (*XkbSetCompatMap_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbDescPtr, int);
+int (*XkbAllocNames_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, int, int);
+int (*XkbGetNames_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbDescPtr);
+int (*XkbSetNames_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int, XkbDescPtr);
+int (*XkbChangeNames_dylibloader_wrapper_xlib)(Display *, XkbDescPtr, XkbNameChangesPtr);
+void (*XkbFreeNames_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, int);
+int (*XkbGetState_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbStatePtr);
+int (*XkbSetMap_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbDescPtr);
+int (*XkbChangeMap_dylibloader_wrapper_xlib)(Display *, XkbDescPtr, XkbMapChangesPtr);
+int (*XkbSetDetectableAutoRepeat_dylibloader_wrapper_xlib)(Display *, int, int *);
+int (*XkbGetDetectableAutoRepeat_dylibloader_wrapper_xlib)(Display *, int *);
+int (*XkbSetAutoResetControls_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int *, unsigned int *);
+int (*XkbGetAutoResetControls_dylibloader_wrapper_xlib)(Display *, unsigned int *, unsigned int *);
+int (*XkbSetPerClientControls_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int *);
+int (*XkbGetPerClientControls_dylibloader_wrapper_xlib)(Display *, unsigned int *);
+int (*XkbCopyKeyType_dylibloader_wrapper_xlib)(XkbKeyTypePtr, XkbKeyTypePtr);
+int (*XkbCopyKeyTypes_dylibloader_wrapper_xlib)(XkbKeyTypePtr, XkbKeyTypePtr, int);
+int (*XkbResizeKeyType_dylibloader_wrapper_xlib)(XkbDescPtr, int, int, int, int);
+KeySym *(*XkbResizeKeySyms_dylibloader_wrapper_xlib)(XkbDescPtr, int, int);
+XkbAction *(*XkbResizeKeyActions_dylibloader_wrapper_xlib)(XkbDescPtr, int, int);
+int (*XkbChangeTypesOfKey_dylibloader_wrapper_xlib)(XkbDescPtr, int, int, unsigned int, int *, XkbMapChangesPtr);
+int (*XkbChangeKeycodeRange_dylibloader_wrapper_xlib)(XkbDescPtr, int, int, XkbChangesPtr);
+XkbComponentListPtr (*XkbListComponents_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbComponentNamesPtr, int *);
+void (*XkbFreeComponentList_dylibloader_wrapper_xlib)(XkbComponentListPtr);
+XkbDescPtr (*XkbGetKeyboard_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int);
+XkbDescPtr (*XkbGetKeyboardByName_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbComponentNamesPtr, unsigned int, unsigned int, int);
+int (*XkbKeyTypesForCoreSymbols_dylibloader_wrapper_xlib)(XkbDescPtr, int, KeySym *, unsigned int, int *, KeySym *);
+int (*XkbApplyCompatMapToKey_dylibloader_wrapper_xlib)(XkbDescPtr, KeyCode, XkbChangesPtr);
+int (*XkbUpdateMapFromCore_dylibloader_wrapper_xlib)(XkbDescPtr, KeyCode, int, int, KeySym *, XkbChangesPtr);
+XkbDeviceLedInfoPtr (*XkbAddDeviceLedInfo_dylibloader_wrapper_xlib)(XkbDeviceInfoPtr, unsigned int, unsigned int);
+int (*XkbResizeDeviceButtonActions_dylibloader_wrapper_xlib)(XkbDeviceInfoPtr, unsigned int);
+XkbDeviceInfoPtr (*XkbAllocDeviceInfo_dylibloader_wrapper_xlib)(unsigned int, unsigned int, unsigned int);
+void (*XkbFreeDeviceInfo_dylibloader_wrapper_xlib)(XkbDeviceInfoPtr, unsigned int, int);
+void (*XkbNoteDeviceChanges_dylibloader_wrapper_xlib)(XkbDeviceChangesPtr, XkbExtensionDeviceNotifyEvent *, unsigned int);
+XkbDeviceInfoPtr (*XkbGetDeviceInfo_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int, unsigned int);
+int (*XkbGetDeviceInfoChanges_dylibloader_wrapper_xlib)(Display *, XkbDeviceInfoPtr, XkbDeviceChangesPtr);
+int (*XkbGetDeviceButtonActions_dylibloader_wrapper_xlib)(Display *, XkbDeviceInfoPtr, int, unsigned int, unsigned int);
+int (*XkbGetDeviceLedInfo_dylibloader_wrapper_xlib)(Display *, XkbDeviceInfoPtr, unsigned int, unsigned int, unsigned int);
+int (*XkbSetDeviceInfo_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbDeviceInfoPtr);
+int (*XkbChangeDeviceInfo_dylibloader_wrapper_xlib)(Display *, XkbDeviceInfoPtr, XkbDeviceChangesPtr);
+int (*XkbSetDeviceLedInfo_dylibloader_wrapper_xlib)(Display *, XkbDeviceInfoPtr, unsigned int, unsigned int, unsigned int);
+int (*XkbSetDeviceButtonActions_dylibloader_wrapper_xlib)(Display *, XkbDeviceInfoPtr, unsigned int, unsigned int);
+char (*XkbToControl_dylibloader_wrapper_xlib)(char);
+int (*XkbSetDebuggingFlags_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, char *, unsigned int, unsigned int, unsigned int *, unsigned int *);
+int (*XkbApplyVirtualModChanges_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, XkbChangesPtr);
+int (*XkbUpdateActionVirtualMods_dylibloader_wrapper_xlib)(XkbDescPtr, XkbAction *, unsigned int);
+void (*XkbUpdateKeyTypeVirtualMods_dylibloader_wrapper_xlib)(XkbDescPtr, XkbKeyTypePtr, unsigned int, XkbChangesPtr);
int initialize_xlib(int verbose) {
void *handle;
char *error;
@@ -2548,6 +2548,14 @@ int initialize_xlib(int verbose) {
fprintf(stderr, "%s\n", error);
}
}
+// XSetIOErrorExitHandler
+ *(void **) (&XSetIOErrorExitHandler_dylibloader_wrapper_xlib) = dlsym(handle, "XSetIOErrorExitHandler");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
// XListPixmapFormats
*(void **) (&XListPixmapFormats_dylibloader_wrapper_xlib) = dlsym(handle, "XListPixmapFormats");
if (verbose) {
@@ -5132,6 +5140,14 @@ int initialize_xlib(int verbose) {
fprintf(stderr, "%s\n", error);
}
}
+// XFreeThreads
+ *(void **) (&XFreeThreads_dylibloader_wrapper_xlib) = dlsym(handle, "XFreeThreads");
+ if (verbose) {
+ error = dlerror();
+ if (error != NULL) {
+ fprintf(stderr, "%s\n", error);
+ }
+ }
// XAllocClassHint
*(void **) (&XAllocClassHint_dylibloader_wrapper_xlib) = dlsym(handle, "XAllocClassHint");
if (verbose) {
diff --git a/platform/linuxbsd/x11/dynwrappers/xlib-so_wrap.h b/platform/linuxbsd/x11/dynwrappers/xlib-so_wrap.h
index 5bad21002d..3f556a7cda 100644
--- a/platform/linuxbsd/x11/dynwrappers/xlib-so_wrap.h
+++ b/platform/linuxbsd/x11/dynwrappers/xlib-so_wrap.h
@@ -2,16 +2,9 @@
#define DYLIBLOAD_WRAPPER_XLIB
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
-// generated by generate-wrapper.py 0.3 on 2023-01-23 15:13:26
-// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/Xlib.h --include ./thirdparty/linuxbsd_headers/X11/Xutil.h --include ./thirdparty/linuxbsd_headers/X11/XKBlib.h --sys-include "thirdparty/linuxbsd_headers/X11/Xlib.h" --sys-include "thirdparty/linuxbsd_headers/X11/Xutil.h" --sys-include "thirdparty/linuxbsd_headers/X11/XKBlib.h" --soname libX11.so.6 --init-name xlib --omit-prefix XkbGetDeviceIndicatorState --omit-prefix XkbAddSymInterpret --output-header ./platform/linuxbsd/x11/dynwrappers/xlib-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xlib-so_wrap.c~
+// generated by generate-wrapper.py 0.6 on 2024-11-09 02:52:36
+// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/Xlib.h --include ./thirdparty/linuxbsd_headers/X11/Xutil.h --include ./thirdparty/linuxbsd_headers/X11/XKBlib.h --sys-include thirdparty/linuxbsd_headers/X11/Xlib.h --sys-include thirdparty/linuxbsd_headers/X11/Xutil.h --sys-include thirdparty/linuxbsd_headers/X11/XKBlib.h --soname libX11.so.6 --init-name xlib --omit-prefix XkbGetDeviceIndicatorState --omit-prefix XkbAddSymInterpret --output-header ./platform/linuxbsd/x11/dynwrappers/xlib-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xlib-so_wrap.c
//
-// NOTE: Generated from Xlib 1.6.9.
-// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, the type of the third argument of
-// XIfEvent, XPeekIfEvent and XCheckIfEvent had to be fixed as it wasn't parsed
-// fully (it's a Bool function pointer, but it was just being parsed as an int
-// pointer).
-
#include <stdint.h>
#define _Xmblen _Xmblen_dylibloader_orig_xlib
@@ -103,6 +96,7 @@
#define XScreenNumberOfScreen XScreenNumberOfScreen_dylibloader_orig_xlib
#define XSetErrorHandler XSetErrorHandler_dylibloader_orig_xlib
#define XSetIOErrorHandler XSetIOErrorHandler_dylibloader_orig_xlib
+#define XSetIOErrorExitHandler XSetIOErrorExitHandler_dylibloader_orig_xlib
#define XListPixmapFormats XListPixmapFormats_dylibloader_orig_xlib
#define XListDepths XListDepths_dylibloader_orig_xlib
#define XReconfigureWMWindow XReconfigureWMWindow_dylibloader_orig_xlib
@@ -426,6 +420,7 @@
#define _Xwctomb _Xwctomb_dylibloader_orig_xlib
#define XGetEventData XGetEventData_dylibloader_orig_xlib
#define XFreeEventData XFreeEventData_dylibloader_orig_xlib
+#define XFreeThreads XFreeThreads_dylibloader_orig_xlib
#define XAllocClassHint XAllocClassHint_dylibloader_orig_xlib
#define XAllocIconSize XAllocIconSize_dylibloader_orig_xlib
#define XAllocSizeHints XAllocSizeHints_dylibloader_orig_xlib
@@ -709,6 +704,7 @@
#undef XScreenNumberOfScreen
#undef XSetErrorHandler
#undef XSetIOErrorHandler
+#undef XSetIOErrorExitHandler
#undef XListPixmapFormats
#undef XListDepths
#undef XReconfigureWMWindow
@@ -1032,6 +1028,7 @@
#undef _Xwctomb
#undef XGetEventData
#undef XFreeEventData
+#undef XFreeThreads
#undef XAllocClassHint
#undef XAllocIconSize
#undef XAllocSizeHints
@@ -1315,6 +1312,7 @@ extern "C" {
#define XScreenNumberOfScreen XScreenNumberOfScreen_dylibloader_wrapper_xlib
#define XSetErrorHandler XSetErrorHandler_dylibloader_wrapper_xlib
#define XSetIOErrorHandler XSetIOErrorHandler_dylibloader_wrapper_xlib
+#define XSetIOErrorExitHandler XSetIOErrorExitHandler_dylibloader_wrapper_xlib
#define XListPixmapFormats XListPixmapFormats_dylibloader_wrapper_xlib
#define XListDepths XListDepths_dylibloader_wrapper_xlib
#define XReconfigureWMWindow XReconfigureWMWindow_dylibloader_wrapper_xlib
@@ -1638,6 +1636,7 @@ extern "C" {
#define _Xwctomb _Xwctomb_dylibloader_wrapper_xlib
#define XGetEventData XGetEventData_dylibloader_wrapper_xlib
#define XFreeEventData XFreeEventData_dylibloader_wrapper_xlib
+#define XFreeThreads XFreeThreads_dylibloader_wrapper_xlib
#define XAllocClassHint XAllocClassHint_dylibloader_wrapper_xlib
#define XAllocIconSize XAllocIconSize_dylibloader_wrapper_xlib
#define XAllocSizeHints XAllocSizeHints_dylibloader_wrapper_xlib
@@ -1829,609 +1828,611 @@ extern "C" {
#define XkbApplyVirtualModChanges XkbApplyVirtualModChanges_dylibloader_wrapper_xlib
#define XkbUpdateActionVirtualMods XkbUpdateActionVirtualMods_dylibloader_wrapper_xlib
#define XkbUpdateKeyTypeVirtualMods XkbUpdateKeyTypeVirtualMods_dylibloader_wrapper_xlib
-extern int (*_Xmblen_dylibloader_wrapper_xlib)( char*, int);
-extern XFontStruct* (*XLoadQueryFont_dylibloader_wrapper_xlib)( Display*,const char*);
-extern XFontStruct* (*XQueryFont_dylibloader_wrapper_xlib)( Display*, XID);
-extern XTimeCoord* (*XGetMotionEvents_dylibloader_wrapper_xlib)( Display*, Window, Time, Time, int*);
-extern XModifierKeymap* (*XDeleteModifiermapEntry_dylibloader_wrapper_xlib)( XModifierKeymap*, KeyCode, int);
-extern XModifierKeymap* (*XGetModifierMapping_dylibloader_wrapper_xlib)( Display*);
-extern XModifierKeymap* (*XInsertModifiermapEntry_dylibloader_wrapper_xlib)( XModifierKeymap*, KeyCode, int);
-extern XModifierKeymap* (*XNewModifiermap_dylibloader_wrapper_xlib)( int);
-extern XImage* (*XCreateImage_dylibloader_wrapper_xlib)( Display*, Visual*, unsigned int, int, int, char*, unsigned int, unsigned int, int, int);
-extern int (*XInitImage_dylibloader_wrapper_xlib)( XImage*);
-extern XImage* (*XGetImage_dylibloader_wrapper_xlib)( Display*, Drawable, int, int, unsigned int, unsigned int, unsigned long, int);
-extern XImage* (*XGetSubImage_dylibloader_wrapper_xlib)( Display*, Drawable, int, int, unsigned int, unsigned int, unsigned long, int, XImage*, int, int);
-extern Display* (*XOpenDisplay_dylibloader_wrapper_xlib)(const char*);
-extern void (*XrmInitialize_dylibloader_wrapper_xlib)( void);
-extern char* (*XFetchBytes_dylibloader_wrapper_xlib)( Display*, int*);
-extern char* (*XFetchBuffer_dylibloader_wrapper_xlib)( Display*, int*, int);
-extern char* (*XGetAtomName_dylibloader_wrapper_xlib)( Display*, Atom);
-extern int (*XGetAtomNames_dylibloader_wrapper_xlib)( Display*, Atom*, int, char**);
-extern char* (*XGetDefault_dylibloader_wrapper_xlib)( Display*,const char*,const char*);
-extern char* (*XDisplayName_dylibloader_wrapper_xlib)(const char*);
-extern char* (*XKeysymToString_dylibloader_wrapper_xlib)( KeySym);
-extern int* (*XSynchronize_dylibloader_wrapper_xlib)( Display*, int);
-extern int* (*XSetAfterFunction_dylibloader_wrapper_xlib)( Display*, int*);
-extern Atom (*XInternAtom_dylibloader_wrapper_xlib)( Display*,const char*, int);
-extern int (*XInternAtoms_dylibloader_wrapper_xlib)( Display*, char**, int, int, Atom*);
-extern Colormap (*XCopyColormapAndFree_dylibloader_wrapper_xlib)( Display*, Colormap);
-extern Colormap (*XCreateColormap_dylibloader_wrapper_xlib)( Display*, Window, Visual*, int);
-extern Cursor (*XCreatePixmapCursor_dylibloader_wrapper_xlib)( Display*, Pixmap, Pixmap, XColor*, XColor*, unsigned int, unsigned int);
-extern Cursor (*XCreateGlyphCursor_dylibloader_wrapper_xlib)( Display*, Font, Font, unsigned int, unsigned int,const XColor*,const XColor*);
-extern Cursor (*XCreateFontCursor_dylibloader_wrapper_xlib)( Display*, unsigned int);
-extern Font (*XLoadFont_dylibloader_wrapper_xlib)( Display*,const char*);
-extern GC (*XCreateGC_dylibloader_wrapper_xlib)( Display*, Drawable, unsigned long, XGCValues*);
-extern GContext (*XGContextFromGC_dylibloader_wrapper_xlib)( GC);
-extern void (*XFlushGC_dylibloader_wrapper_xlib)( Display*, GC);
-extern Pixmap (*XCreatePixmap_dylibloader_wrapper_xlib)( Display*, Drawable, unsigned int, unsigned int, unsigned int);
-extern Pixmap (*XCreateBitmapFromData_dylibloader_wrapper_xlib)( Display*, Drawable,const char*, unsigned int, unsigned int);
-extern Pixmap (*XCreatePixmapFromBitmapData_dylibloader_wrapper_xlib)( Display*, Drawable, char*, unsigned int, unsigned int, unsigned long, unsigned long, unsigned int);
-extern Window (*XCreateSimpleWindow_dylibloader_wrapper_xlib)( Display*, Window, int, int, unsigned int, unsigned int, unsigned int, unsigned long, unsigned long);
-extern Window (*XGetSelectionOwner_dylibloader_wrapper_xlib)( Display*, Atom);
-extern Window (*XCreateWindow_dylibloader_wrapper_xlib)( Display*, Window, int, int, unsigned int, unsigned int, unsigned int, int, unsigned int, Visual*, unsigned long, XSetWindowAttributes*);
-extern Colormap* (*XListInstalledColormaps_dylibloader_wrapper_xlib)( Display*, Window, int*);
-extern char** (*XListFonts_dylibloader_wrapper_xlib)( Display*,const char*, int, int*);
-extern char** (*XListFontsWithInfo_dylibloader_wrapper_xlib)( Display*,const char*, int, int*, XFontStruct**);
-extern char** (*XGetFontPath_dylibloader_wrapper_xlib)( Display*, int*);
-extern char** (*XListExtensions_dylibloader_wrapper_xlib)( Display*, int*);
-extern Atom* (*XListProperties_dylibloader_wrapper_xlib)( Display*, Window, int*);
-extern XHostAddress* (*XListHosts_dylibloader_wrapper_xlib)( Display*, int*, int*);
-extern KeySym (*XKeycodeToKeysym_dylibloader_wrapper_xlib)( Display*, KeyCode, int);
-extern KeySym (*XLookupKeysym_dylibloader_wrapper_xlib)( XKeyEvent*, int);
-extern KeySym* (*XGetKeyboardMapping_dylibloader_wrapper_xlib)( Display*, KeyCode, int, int*);
-extern KeySym (*XStringToKeysym_dylibloader_wrapper_xlib)(const char*);
-extern long (*XMaxRequestSize_dylibloader_wrapper_xlib)( Display*);
-extern long (*XExtendedMaxRequestSize_dylibloader_wrapper_xlib)( Display*);
-extern char* (*XResourceManagerString_dylibloader_wrapper_xlib)( Display*);
-extern char* (*XScreenResourceString_dylibloader_wrapper_xlib)( Screen*);
-extern unsigned long (*XDisplayMotionBufferSize_dylibloader_wrapper_xlib)( Display*);
-extern VisualID (*XVisualIDFromVisual_dylibloader_wrapper_xlib)( Visual*);
-extern int (*XInitThreads_dylibloader_wrapper_xlib)( void);
-extern void (*XLockDisplay_dylibloader_wrapper_xlib)( Display*);
-extern void (*XUnlockDisplay_dylibloader_wrapper_xlib)( Display*);
-extern XExtCodes* (*XInitExtension_dylibloader_wrapper_xlib)( Display*,const char*);
-extern XExtCodes* (*XAddExtension_dylibloader_wrapper_xlib)( Display*);
-extern XExtData* (*XFindOnExtensionList_dylibloader_wrapper_xlib)( XExtData**, int);
-extern XExtData** (*XEHeadOfExtensionList_dylibloader_wrapper_xlib)( XEDataObject);
-extern Window (*XRootWindow_dylibloader_wrapper_xlib)( Display*, int);
-extern Window (*XDefaultRootWindow_dylibloader_wrapper_xlib)( Display*);
-extern Window (*XRootWindowOfScreen_dylibloader_wrapper_xlib)( Screen*);
-extern Visual* (*XDefaultVisual_dylibloader_wrapper_xlib)( Display*, int);
-extern Visual* (*XDefaultVisualOfScreen_dylibloader_wrapper_xlib)( Screen*);
-extern GC (*XDefaultGC_dylibloader_wrapper_xlib)( Display*, int);
-extern GC (*XDefaultGCOfScreen_dylibloader_wrapper_xlib)( Screen*);
-extern unsigned long (*XBlackPixel_dylibloader_wrapper_xlib)( Display*, int);
-extern unsigned long (*XWhitePixel_dylibloader_wrapper_xlib)( Display*, int);
-extern unsigned long (*XAllPlanes_dylibloader_wrapper_xlib)( void);
-extern unsigned long (*XBlackPixelOfScreen_dylibloader_wrapper_xlib)( Screen*);
-extern unsigned long (*XWhitePixelOfScreen_dylibloader_wrapper_xlib)( Screen*);
-extern unsigned long (*XNextRequest_dylibloader_wrapper_xlib)( Display*);
-extern unsigned long (*XLastKnownRequestProcessed_dylibloader_wrapper_xlib)( Display*);
-extern char* (*XServerVendor_dylibloader_wrapper_xlib)( Display*);
-extern char* (*XDisplayString_dylibloader_wrapper_xlib)( Display*);
-extern Colormap (*XDefaultColormap_dylibloader_wrapper_xlib)( Display*, int);
-extern Colormap (*XDefaultColormapOfScreen_dylibloader_wrapper_xlib)( Screen*);
-extern Display* (*XDisplayOfScreen_dylibloader_wrapper_xlib)( Screen*);
-extern Screen* (*XScreenOfDisplay_dylibloader_wrapper_xlib)( Display*, int);
-extern Screen* (*XDefaultScreenOfDisplay_dylibloader_wrapper_xlib)( Display*);
-extern long (*XEventMaskOfScreen_dylibloader_wrapper_xlib)( Screen*);
-extern int (*XScreenNumberOfScreen_dylibloader_wrapper_xlib)( Screen*);
-extern XErrorHandler (*XSetErrorHandler_dylibloader_wrapper_xlib)( XErrorHandler);
-extern XIOErrorHandler (*XSetIOErrorHandler_dylibloader_wrapper_xlib)( XIOErrorHandler);
-extern XPixmapFormatValues* (*XListPixmapFormats_dylibloader_wrapper_xlib)( Display*, int*);
-extern int* (*XListDepths_dylibloader_wrapper_xlib)( Display*, int, int*);
-extern int (*XReconfigureWMWindow_dylibloader_wrapper_xlib)( Display*, Window, int, unsigned int, XWindowChanges*);
-extern int (*XGetWMProtocols_dylibloader_wrapper_xlib)( Display*, Window, Atom**, int*);
-extern int (*XSetWMProtocols_dylibloader_wrapper_xlib)( Display*, Window, Atom*, int);
-extern int (*XIconifyWindow_dylibloader_wrapper_xlib)( Display*, Window, int);
-extern int (*XWithdrawWindow_dylibloader_wrapper_xlib)( Display*, Window, int);
-extern int (*XGetCommand_dylibloader_wrapper_xlib)( Display*, Window, char***, int*);
-extern int (*XGetWMColormapWindows_dylibloader_wrapper_xlib)( Display*, Window, Window**, int*);
-extern int (*XSetWMColormapWindows_dylibloader_wrapper_xlib)( Display*, Window, Window*, int);
-extern void (*XFreeStringList_dylibloader_wrapper_xlib)( char**);
-extern int (*XSetTransientForHint_dylibloader_wrapper_xlib)( Display*, Window, Window);
-extern int (*XActivateScreenSaver_dylibloader_wrapper_xlib)( Display*);
-extern int (*XAddHost_dylibloader_wrapper_xlib)( Display*, XHostAddress*);
-extern int (*XAddHosts_dylibloader_wrapper_xlib)( Display*, XHostAddress*, int);
-extern int (*XAddToExtensionList_dylibloader_wrapper_xlib)(struct _XExtData**, XExtData*);
-extern int (*XAddToSaveSet_dylibloader_wrapper_xlib)( Display*, Window);
-extern int (*XAllocColor_dylibloader_wrapper_xlib)( Display*, Colormap, XColor*);
-extern int (*XAllocColorCells_dylibloader_wrapper_xlib)( Display*, Colormap, int, unsigned long*, unsigned int, unsigned long*, unsigned int);
-extern int (*XAllocColorPlanes_dylibloader_wrapper_xlib)( Display*, Colormap, int, unsigned long*, int, int, int, int, unsigned long*, unsigned long*, unsigned long*);
-extern int (*XAllocNamedColor_dylibloader_wrapper_xlib)( Display*, Colormap,const char*, XColor*, XColor*);
-extern int (*XAllowEvents_dylibloader_wrapper_xlib)( Display*, int, Time);
-extern int (*XAutoRepeatOff_dylibloader_wrapper_xlib)( Display*);
-extern int (*XAutoRepeatOn_dylibloader_wrapper_xlib)( Display*);
-extern int (*XBell_dylibloader_wrapper_xlib)( Display*, int);
-extern int (*XBitmapBitOrder_dylibloader_wrapper_xlib)( Display*);
-extern int (*XBitmapPad_dylibloader_wrapper_xlib)( Display*);
-extern int (*XBitmapUnit_dylibloader_wrapper_xlib)( Display*);
-extern int (*XCellsOfScreen_dylibloader_wrapper_xlib)( Screen*);
-extern int (*XChangeActivePointerGrab_dylibloader_wrapper_xlib)( Display*, unsigned int, Cursor, Time);
-extern int (*XChangeGC_dylibloader_wrapper_xlib)( Display*, GC, unsigned long, XGCValues*);
-extern int (*XChangeKeyboardControl_dylibloader_wrapper_xlib)( Display*, unsigned long, XKeyboardControl*);
-extern int (*XChangeKeyboardMapping_dylibloader_wrapper_xlib)( Display*, int, int, KeySym*, int);
-extern int (*XChangePointerControl_dylibloader_wrapper_xlib)( Display*, int, int, int, int, int);
-extern int (*XChangeProperty_dylibloader_wrapper_xlib)( Display*, Window, Atom, Atom, int, int,const unsigned char*, int);
-extern int (*XChangeSaveSet_dylibloader_wrapper_xlib)( Display*, Window, int);
-extern int (*XChangeWindowAttributes_dylibloader_wrapper_xlib)( Display*, Window, unsigned long, XSetWindowAttributes*);
-extern int (*XCheckIfEvent_dylibloader_wrapper_xlib)( Display*, XEvent*, Bool (*) (Display*, XEvent*, XPointer), XPointer);
-extern int (*XCheckMaskEvent_dylibloader_wrapper_xlib)( Display*, long, XEvent*);
-extern int (*XCheckTypedEvent_dylibloader_wrapper_xlib)( Display*, int, XEvent*);
-extern int (*XCheckTypedWindowEvent_dylibloader_wrapper_xlib)( Display*, Window, int, XEvent*);
-extern int (*XCheckWindowEvent_dylibloader_wrapper_xlib)( Display*, Window, long, XEvent*);
-extern int (*XCirculateSubwindows_dylibloader_wrapper_xlib)( Display*, Window, int);
-extern int (*XCirculateSubwindowsDown_dylibloader_wrapper_xlib)( Display*, Window);
-extern int (*XCirculateSubwindowsUp_dylibloader_wrapper_xlib)( Display*, Window);
-extern int (*XClearArea_dylibloader_wrapper_xlib)( Display*, Window, int, int, unsigned int, unsigned int, int);
-extern int (*XClearWindow_dylibloader_wrapper_xlib)( Display*, Window);
-extern int (*XCloseDisplay_dylibloader_wrapper_xlib)( Display*);
-extern int (*XConfigureWindow_dylibloader_wrapper_xlib)( Display*, Window, unsigned int, XWindowChanges*);
-extern int (*XConnectionNumber_dylibloader_wrapper_xlib)( Display*);
-extern int (*XConvertSelection_dylibloader_wrapper_xlib)( Display*, Atom, Atom, Atom, Window, Time);
-extern int (*XCopyArea_dylibloader_wrapper_xlib)( Display*, Drawable, Drawable, GC, int, int, unsigned int, unsigned int, int, int);
-extern int (*XCopyGC_dylibloader_wrapper_xlib)( Display*, GC, unsigned long, GC);
-extern int (*XCopyPlane_dylibloader_wrapper_xlib)( Display*, Drawable, Drawable, GC, int, int, unsigned int, unsigned int, int, int, unsigned long);
-extern int (*XDefaultDepth_dylibloader_wrapper_xlib)( Display*, int);
-extern int (*XDefaultDepthOfScreen_dylibloader_wrapper_xlib)( Screen*);
-extern int (*XDefaultScreen_dylibloader_wrapper_xlib)( Display*);
-extern int (*XDefineCursor_dylibloader_wrapper_xlib)( Display*, Window, Cursor);
-extern int (*XDeleteProperty_dylibloader_wrapper_xlib)( Display*, Window, Atom);
-extern int (*XDestroyWindow_dylibloader_wrapper_xlib)( Display*, Window);
-extern int (*XDestroySubwindows_dylibloader_wrapper_xlib)( Display*, Window);
-extern int (*XDoesBackingStore_dylibloader_wrapper_xlib)( Screen*);
-extern int (*XDoesSaveUnders_dylibloader_wrapper_xlib)( Screen*);
-extern int (*XDisableAccessControl_dylibloader_wrapper_xlib)( Display*);
-extern int (*XDisplayCells_dylibloader_wrapper_xlib)( Display*, int);
-extern int (*XDisplayHeight_dylibloader_wrapper_xlib)( Display*, int);
-extern int (*XDisplayHeightMM_dylibloader_wrapper_xlib)( Display*, int);
-extern int (*XDisplayKeycodes_dylibloader_wrapper_xlib)( Display*, int*, int*);
-extern int (*XDisplayPlanes_dylibloader_wrapper_xlib)( Display*, int);
-extern int (*XDisplayWidth_dylibloader_wrapper_xlib)( Display*, int);
-extern int (*XDisplayWidthMM_dylibloader_wrapper_xlib)( Display*, int);
-extern int (*XDrawArc_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, unsigned int, unsigned int, int, int);
-extern int (*XDrawArcs_dylibloader_wrapper_xlib)( Display*, Drawable, GC, XArc*, int);
-extern int (*XDrawImageString_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int,const char*, int);
-extern int (*XDrawImageString16_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int,const XChar2b*, int);
-extern int (*XDrawLine_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, int, int);
-extern int (*XDrawLines_dylibloader_wrapper_xlib)( Display*, Drawable, GC, XPoint*, int, int);
-extern int (*XDrawPoint_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int);
-extern int (*XDrawPoints_dylibloader_wrapper_xlib)( Display*, Drawable, GC, XPoint*, int, int);
-extern int (*XDrawRectangle_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, unsigned int, unsigned int);
-extern int (*XDrawRectangles_dylibloader_wrapper_xlib)( Display*, Drawable, GC, XRectangle*, int);
-extern int (*XDrawSegments_dylibloader_wrapper_xlib)( Display*, Drawable, GC, XSegment*, int);
-extern int (*XDrawString_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int,const char*, int);
-extern int (*XDrawString16_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int,const XChar2b*, int);
-extern int (*XDrawText_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, XTextItem*, int);
-extern int (*XDrawText16_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, XTextItem16*, int);
-extern int (*XEnableAccessControl_dylibloader_wrapper_xlib)( Display*);
-extern int (*XEventsQueued_dylibloader_wrapper_xlib)( Display*, int);
-extern int (*XFetchName_dylibloader_wrapper_xlib)( Display*, Window, char**);
-extern int (*XFillArc_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, unsigned int, unsigned int, int, int);
-extern int (*XFillArcs_dylibloader_wrapper_xlib)( Display*, Drawable, GC, XArc*, int);
-extern int (*XFillPolygon_dylibloader_wrapper_xlib)( Display*, Drawable, GC, XPoint*, int, int, int);
-extern int (*XFillRectangle_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, unsigned int, unsigned int);
-extern int (*XFillRectangles_dylibloader_wrapper_xlib)( Display*, Drawable, GC, XRectangle*, int);
-extern int (*XFlush_dylibloader_wrapper_xlib)( Display*);
-extern int (*XForceScreenSaver_dylibloader_wrapper_xlib)( Display*, int);
-extern int (*XFree_dylibloader_wrapper_xlib)( void*);
-extern int (*XFreeColormap_dylibloader_wrapper_xlib)( Display*, Colormap);
-extern int (*XFreeColors_dylibloader_wrapper_xlib)( Display*, Colormap, unsigned long*, int, unsigned long);
-extern int (*XFreeCursor_dylibloader_wrapper_xlib)( Display*, Cursor);
-extern int (*XFreeExtensionList_dylibloader_wrapper_xlib)( char**);
-extern int (*XFreeFont_dylibloader_wrapper_xlib)( Display*, XFontStruct*);
-extern int (*XFreeFontInfo_dylibloader_wrapper_xlib)( char**, XFontStruct*, int);
-extern int (*XFreeFontNames_dylibloader_wrapper_xlib)( char**);
-extern int (*XFreeFontPath_dylibloader_wrapper_xlib)( char**);
-extern int (*XFreeGC_dylibloader_wrapper_xlib)( Display*, GC);
-extern int (*XFreeModifiermap_dylibloader_wrapper_xlib)( XModifierKeymap*);
-extern int (*XFreePixmap_dylibloader_wrapper_xlib)( Display*, Pixmap);
-extern int (*XGeometry_dylibloader_wrapper_xlib)( Display*, int,const char*,const char*, unsigned int, unsigned int, unsigned int, int, int, int*, int*, int*, int*);
-extern int (*XGetErrorDatabaseText_dylibloader_wrapper_xlib)( Display*,const char*,const char*,const char*, char*, int);
-extern int (*XGetErrorText_dylibloader_wrapper_xlib)( Display*, int, char*, int);
-extern int (*XGetFontProperty_dylibloader_wrapper_xlib)( XFontStruct*, Atom, unsigned long*);
-extern int (*XGetGCValues_dylibloader_wrapper_xlib)( Display*, GC, unsigned long, XGCValues*);
-extern int (*XGetGeometry_dylibloader_wrapper_xlib)( Display*, Drawable, Window*, int*, int*, unsigned int*, unsigned int*, unsigned int*, unsigned int*);
-extern int (*XGetIconName_dylibloader_wrapper_xlib)( Display*, Window, char**);
-extern int (*XGetInputFocus_dylibloader_wrapper_xlib)( Display*, Window*, int*);
-extern int (*XGetKeyboardControl_dylibloader_wrapper_xlib)( Display*, XKeyboardState*);
-extern int (*XGetPointerControl_dylibloader_wrapper_xlib)( Display*, int*, int*, int*);
-extern int (*XGetPointerMapping_dylibloader_wrapper_xlib)( Display*, unsigned char*, int);
-extern int (*XGetScreenSaver_dylibloader_wrapper_xlib)( Display*, int*, int*, int*, int*);
-extern int (*XGetTransientForHint_dylibloader_wrapper_xlib)( Display*, Window, Window*);
-extern int (*XGetWindowProperty_dylibloader_wrapper_xlib)( Display*, Window, Atom, long, long, int, Atom, Atom*, int*, unsigned long*, unsigned long*, unsigned char**);
-extern int (*XGetWindowAttributes_dylibloader_wrapper_xlib)( Display*, Window, XWindowAttributes*);
-extern int (*XGrabButton_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, Window, int, unsigned int, int, int, Window, Cursor);
-extern int (*XGrabKey_dylibloader_wrapper_xlib)( Display*, int, unsigned int, Window, int, int, int);
-extern int (*XGrabKeyboard_dylibloader_wrapper_xlib)( Display*, Window, int, int, int, Time);
-extern int (*XGrabPointer_dylibloader_wrapper_xlib)( Display*, Window, int, unsigned int, int, int, Window, Cursor, Time);
-extern int (*XGrabServer_dylibloader_wrapper_xlib)( Display*);
-extern int (*XHeightMMOfScreen_dylibloader_wrapper_xlib)( Screen*);
-extern int (*XHeightOfScreen_dylibloader_wrapper_xlib)( Screen*);
-extern int (*XIfEvent_dylibloader_wrapper_xlib)( Display*, XEvent*, Bool (*) (Display*, XEvent*, XPointer), XPointer);
-extern int (*XImageByteOrder_dylibloader_wrapper_xlib)( Display*);
-extern int (*XInstallColormap_dylibloader_wrapper_xlib)( Display*, Colormap);
-extern KeyCode (*XKeysymToKeycode_dylibloader_wrapper_xlib)( Display*, KeySym);
-extern int (*XKillClient_dylibloader_wrapper_xlib)( Display*, XID);
-extern int (*XLookupColor_dylibloader_wrapper_xlib)( Display*, Colormap,const char*, XColor*, XColor*);
-extern int (*XLowerWindow_dylibloader_wrapper_xlib)( Display*, Window);
-extern int (*XMapRaised_dylibloader_wrapper_xlib)( Display*, Window);
-extern int (*XMapSubwindows_dylibloader_wrapper_xlib)( Display*, Window);
-extern int (*XMapWindow_dylibloader_wrapper_xlib)( Display*, Window);
-extern int (*XMaskEvent_dylibloader_wrapper_xlib)( Display*, long, XEvent*);
-extern int (*XMaxCmapsOfScreen_dylibloader_wrapper_xlib)( Screen*);
-extern int (*XMinCmapsOfScreen_dylibloader_wrapper_xlib)( Screen*);
-extern int (*XMoveResizeWindow_dylibloader_wrapper_xlib)( Display*, Window, int, int, unsigned int, unsigned int);
-extern int (*XMoveWindow_dylibloader_wrapper_xlib)( Display*, Window, int, int);
-extern int (*XNextEvent_dylibloader_wrapper_xlib)( Display*, XEvent*);
-extern int (*XNoOp_dylibloader_wrapper_xlib)( Display*);
-extern int (*XParseColor_dylibloader_wrapper_xlib)( Display*, Colormap,const char*, XColor*);
-extern int (*XParseGeometry_dylibloader_wrapper_xlib)(const char*, int*, int*, unsigned int*, unsigned int*);
-extern int (*XPeekEvent_dylibloader_wrapper_xlib)( Display*, XEvent*);
-extern int (*XPeekIfEvent_dylibloader_wrapper_xlib)( Display*, XEvent*, Bool (*) (Display*, XEvent*, XPointer), XPointer);
-extern int (*XPending_dylibloader_wrapper_xlib)( Display*);
-extern int (*XPlanesOfScreen_dylibloader_wrapper_xlib)( Screen*);
-extern int (*XProtocolRevision_dylibloader_wrapper_xlib)( Display*);
-extern int (*XProtocolVersion_dylibloader_wrapper_xlib)( Display*);
-extern int (*XPutBackEvent_dylibloader_wrapper_xlib)( Display*, XEvent*);
-extern int (*XPutImage_dylibloader_wrapper_xlib)( Display*, Drawable, GC, XImage*, int, int, int, int, unsigned int, unsigned int);
-extern int (*XQLength_dylibloader_wrapper_xlib)( Display*);
-extern int (*XQueryBestCursor_dylibloader_wrapper_xlib)( Display*, Drawable, unsigned int, unsigned int, unsigned int*, unsigned int*);
-extern int (*XQueryBestSize_dylibloader_wrapper_xlib)( Display*, int, Drawable, unsigned int, unsigned int, unsigned int*, unsigned int*);
-extern int (*XQueryBestStipple_dylibloader_wrapper_xlib)( Display*, Drawable, unsigned int, unsigned int, unsigned int*, unsigned int*);
-extern int (*XQueryBestTile_dylibloader_wrapper_xlib)( Display*, Drawable, unsigned int, unsigned int, unsigned int*, unsigned int*);
-extern int (*XQueryColor_dylibloader_wrapper_xlib)( Display*, Colormap, XColor*);
-extern int (*XQueryColors_dylibloader_wrapper_xlib)( Display*, Colormap, XColor*, int);
-extern int (*XQueryExtension_dylibloader_wrapper_xlib)( Display*,const char*, int*, int*, int*);
-extern int (*XQueryKeymap_dylibloader_wrapper_xlib)( Display*, char [32]);
-extern int (*XQueryPointer_dylibloader_wrapper_xlib)( Display*, Window, Window*, Window*, int*, int*, int*, int*, unsigned int*);
-extern int (*XQueryTextExtents_dylibloader_wrapper_xlib)( Display*, XID,const char*, int, int*, int*, int*, XCharStruct*);
-extern int (*XQueryTextExtents16_dylibloader_wrapper_xlib)( Display*, XID,const XChar2b*, int, int*, int*, int*, XCharStruct*);
-extern int (*XQueryTree_dylibloader_wrapper_xlib)( Display*, Window, Window*, Window*, Window**, unsigned int*);
-extern int (*XRaiseWindow_dylibloader_wrapper_xlib)( Display*, Window);
-extern int (*XReadBitmapFile_dylibloader_wrapper_xlib)( Display*, Drawable,const char*, unsigned int*, unsigned int*, Pixmap*, int*, int*);
-extern int (*XReadBitmapFileData_dylibloader_wrapper_xlib)(const char*, unsigned int*, unsigned int*, unsigned char**, int*, int*);
-extern int (*XRebindKeysym_dylibloader_wrapper_xlib)( Display*, KeySym, KeySym*, int,const unsigned char*, int);
-extern int (*XRecolorCursor_dylibloader_wrapper_xlib)( Display*, Cursor, XColor*, XColor*);
-extern int (*XRefreshKeyboardMapping_dylibloader_wrapper_xlib)( XMappingEvent*);
-extern int (*XRemoveFromSaveSet_dylibloader_wrapper_xlib)( Display*, Window);
-extern int (*XRemoveHost_dylibloader_wrapper_xlib)( Display*, XHostAddress*);
-extern int (*XRemoveHosts_dylibloader_wrapper_xlib)( Display*, XHostAddress*, int);
-extern int (*XReparentWindow_dylibloader_wrapper_xlib)( Display*, Window, Window, int, int);
-extern int (*XResetScreenSaver_dylibloader_wrapper_xlib)( Display*);
-extern int (*XResizeWindow_dylibloader_wrapper_xlib)( Display*, Window, unsigned int, unsigned int);
-extern int (*XRestackWindows_dylibloader_wrapper_xlib)( Display*, Window*, int);
-extern int (*XRotateBuffers_dylibloader_wrapper_xlib)( Display*, int);
-extern int (*XRotateWindowProperties_dylibloader_wrapper_xlib)( Display*, Window, Atom*, int, int);
-extern int (*XScreenCount_dylibloader_wrapper_xlib)( Display*);
-extern int (*XSelectInput_dylibloader_wrapper_xlib)( Display*, Window, long);
-extern int (*XSendEvent_dylibloader_wrapper_xlib)( Display*, Window, int, long, XEvent*);
-extern int (*XSetAccessControl_dylibloader_wrapper_xlib)( Display*, int);
-extern int (*XSetArcMode_dylibloader_wrapper_xlib)( Display*, GC, int);
-extern int (*XSetBackground_dylibloader_wrapper_xlib)( Display*, GC, unsigned long);
-extern int (*XSetClipMask_dylibloader_wrapper_xlib)( Display*, GC, Pixmap);
-extern int (*XSetClipOrigin_dylibloader_wrapper_xlib)( Display*, GC, int, int);
-extern int (*XSetClipRectangles_dylibloader_wrapper_xlib)( Display*, GC, int, int, XRectangle*, int, int);
-extern int (*XSetCloseDownMode_dylibloader_wrapper_xlib)( Display*, int);
-extern int (*XSetCommand_dylibloader_wrapper_xlib)( Display*, Window, char**, int);
-extern int (*XSetDashes_dylibloader_wrapper_xlib)( Display*, GC, int,const char*, int);
-extern int (*XSetFillRule_dylibloader_wrapper_xlib)( Display*, GC, int);
-extern int (*XSetFillStyle_dylibloader_wrapper_xlib)( Display*, GC, int);
-extern int (*XSetFont_dylibloader_wrapper_xlib)( Display*, GC, Font);
-extern int (*XSetFontPath_dylibloader_wrapper_xlib)( Display*, char**, int);
-extern int (*XSetForeground_dylibloader_wrapper_xlib)( Display*, GC, unsigned long);
-extern int (*XSetFunction_dylibloader_wrapper_xlib)( Display*, GC, int);
-extern int (*XSetGraphicsExposures_dylibloader_wrapper_xlib)( Display*, GC, int);
-extern int (*XSetIconName_dylibloader_wrapper_xlib)( Display*, Window,const char*);
-extern int (*XSetInputFocus_dylibloader_wrapper_xlib)( Display*, Window, int, Time);
-extern int (*XSetLineAttributes_dylibloader_wrapper_xlib)( Display*, GC, unsigned int, int, int, int);
-extern int (*XSetModifierMapping_dylibloader_wrapper_xlib)( Display*, XModifierKeymap*);
-extern int (*XSetPlaneMask_dylibloader_wrapper_xlib)( Display*, GC, unsigned long);
-extern int (*XSetPointerMapping_dylibloader_wrapper_xlib)( Display*,const unsigned char*, int);
-extern int (*XSetScreenSaver_dylibloader_wrapper_xlib)( Display*, int, int, int, int);
-extern int (*XSetSelectionOwner_dylibloader_wrapper_xlib)( Display*, Atom, Window, Time);
-extern int (*XSetState_dylibloader_wrapper_xlib)( Display*, GC, unsigned long, unsigned long, int, unsigned long);
-extern int (*XSetStipple_dylibloader_wrapper_xlib)( Display*, GC, Pixmap);
-extern int (*XSetSubwindowMode_dylibloader_wrapper_xlib)( Display*, GC, int);
-extern int (*XSetTSOrigin_dylibloader_wrapper_xlib)( Display*, GC, int, int);
-extern int (*XSetTile_dylibloader_wrapper_xlib)( Display*, GC, Pixmap);
-extern int (*XSetWindowBackground_dylibloader_wrapper_xlib)( Display*, Window, unsigned long);
-extern int (*XSetWindowBackgroundPixmap_dylibloader_wrapper_xlib)( Display*, Window, Pixmap);
-extern int (*XSetWindowBorder_dylibloader_wrapper_xlib)( Display*, Window, unsigned long);
-extern int (*XSetWindowBorderPixmap_dylibloader_wrapper_xlib)( Display*, Window, Pixmap);
-extern int (*XSetWindowBorderWidth_dylibloader_wrapper_xlib)( Display*, Window, unsigned int);
-extern int (*XSetWindowColormap_dylibloader_wrapper_xlib)( Display*, Window, Colormap);
-extern int (*XStoreBuffer_dylibloader_wrapper_xlib)( Display*,const char*, int, int);
-extern int (*XStoreBytes_dylibloader_wrapper_xlib)( Display*,const char*, int);
-extern int (*XStoreColor_dylibloader_wrapper_xlib)( Display*, Colormap, XColor*);
-extern int (*XStoreColors_dylibloader_wrapper_xlib)( Display*, Colormap, XColor*, int);
-extern int (*XStoreName_dylibloader_wrapper_xlib)( Display*, Window,const char*);
-extern int (*XStoreNamedColor_dylibloader_wrapper_xlib)( Display*, Colormap,const char*, unsigned long, int);
-extern int (*XSync_dylibloader_wrapper_xlib)( Display*, int);
-extern int (*XTextExtents_dylibloader_wrapper_xlib)( XFontStruct*,const char*, int, int*, int*, int*, XCharStruct*);
-extern int (*XTextExtents16_dylibloader_wrapper_xlib)( XFontStruct*,const XChar2b*, int, int*, int*, int*, XCharStruct*);
-extern int (*XTextWidth_dylibloader_wrapper_xlib)( XFontStruct*,const char*, int);
-extern int (*XTextWidth16_dylibloader_wrapper_xlib)( XFontStruct*,const XChar2b*, int);
-extern int (*XTranslateCoordinates_dylibloader_wrapper_xlib)( Display*, Window, Window, int, int, int*, int*, Window*);
-extern int (*XUndefineCursor_dylibloader_wrapper_xlib)( Display*, Window);
-extern int (*XUngrabButton_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, Window);
-extern int (*XUngrabKey_dylibloader_wrapper_xlib)( Display*, int, unsigned int, Window);
-extern int (*XUngrabKeyboard_dylibloader_wrapper_xlib)( Display*, Time);
-extern int (*XUngrabPointer_dylibloader_wrapper_xlib)( Display*, Time);
-extern int (*XUngrabServer_dylibloader_wrapper_xlib)( Display*);
-extern int (*XUninstallColormap_dylibloader_wrapper_xlib)( Display*, Colormap);
-extern int (*XUnloadFont_dylibloader_wrapper_xlib)( Display*, Font);
-extern int (*XUnmapSubwindows_dylibloader_wrapper_xlib)( Display*, Window);
-extern int (*XUnmapWindow_dylibloader_wrapper_xlib)( Display*, Window);
-extern int (*XVendorRelease_dylibloader_wrapper_xlib)( Display*);
-extern int (*XWarpPointer_dylibloader_wrapper_xlib)( Display*, Window, Window, int, int, unsigned int, unsigned int, int, int);
-extern int (*XWidthMMOfScreen_dylibloader_wrapper_xlib)( Screen*);
-extern int (*XWidthOfScreen_dylibloader_wrapper_xlib)( Screen*);
-extern int (*XWindowEvent_dylibloader_wrapper_xlib)( Display*, Window, long, XEvent*);
-extern int (*XWriteBitmapFile_dylibloader_wrapper_xlib)( Display*,const char*, Pixmap, unsigned int, unsigned int, int, int);
-extern int (*XSupportsLocale_dylibloader_wrapper_xlib)( void);
-extern char* (*XSetLocaleModifiers_dylibloader_wrapper_xlib)(const char*);
-extern XOM (*XOpenOM_dylibloader_wrapper_xlib)( Display*,struct _XrmHashBucketRec*,const char*,const char*);
-extern int (*XCloseOM_dylibloader_wrapper_xlib)( XOM);
-extern char* (*XSetOMValues_dylibloader_wrapper_xlib)( XOM,...);
-extern char* (*XGetOMValues_dylibloader_wrapper_xlib)( XOM,...);
-extern Display* (*XDisplayOfOM_dylibloader_wrapper_xlib)( XOM);
-extern char* (*XLocaleOfOM_dylibloader_wrapper_xlib)( XOM);
-extern XOC (*XCreateOC_dylibloader_wrapper_xlib)( XOM,...);
-extern void (*XDestroyOC_dylibloader_wrapper_xlib)( XOC);
-extern XOM (*XOMOfOC_dylibloader_wrapper_xlib)( XOC);
-extern char* (*XSetOCValues_dylibloader_wrapper_xlib)( XOC,...);
-extern char* (*XGetOCValues_dylibloader_wrapper_xlib)( XOC,...);
-extern XFontSet (*XCreateFontSet_dylibloader_wrapper_xlib)( Display*,const char*, char***, int*, char**);
-extern void (*XFreeFontSet_dylibloader_wrapper_xlib)( Display*, XFontSet);
-extern int (*XFontsOfFontSet_dylibloader_wrapper_xlib)( XFontSet, XFontStruct***, char***);
-extern char* (*XBaseFontNameListOfFontSet_dylibloader_wrapper_xlib)( XFontSet);
-extern char* (*XLocaleOfFontSet_dylibloader_wrapper_xlib)( XFontSet);
-extern int (*XContextDependentDrawing_dylibloader_wrapper_xlib)( XFontSet);
-extern int (*XDirectionalDependentDrawing_dylibloader_wrapper_xlib)( XFontSet);
-extern int (*XContextualDrawing_dylibloader_wrapper_xlib)( XFontSet);
-extern XFontSetExtents* (*XExtentsOfFontSet_dylibloader_wrapper_xlib)( XFontSet);
-extern int (*XmbTextEscapement_dylibloader_wrapper_xlib)( XFontSet,const char*, int);
-extern int (*XwcTextEscapement_dylibloader_wrapper_xlib)( XFontSet,const wchar_t*, int);
-extern int (*Xutf8TextEscapement_dylibloader_wrapper_xlib)( XFontSet,const char*, int);
-extern int (*XmbTextExtents_dylibloader_wrapper_xlib)( XFontSet,const char*, int, XRectangle*, XRectangle*);
-extern int (*XwcTextExtents_dylibloader_wrapper_xlib)( XFontSet,const wchar_t*, int, XRectangle*, XRectangle*);
-extern int (*Xutf8TextExtents_dylibloader_wrapper_xlib)( XFontSet,const char*, int, XRectangle*, XRectangle*);
-extern int (*XmbTextPerCharExtents_dylibloader_wrapper_xlib)( XFontSet,const char*, int, XRectangle*, XRectangle*, int, int*, XRectangle*, XRectangle*);
-extern int (*XwcTextPerCharExtents_dylibloader_wrapper_xlib)( XFontSet,const wchar_t*, int, XRectangle*, XRectangle*, int, int*, XRectangle*, XRectangle*);
-extern int (*Xutf8TextPerCharExtents_dylibloader_wrapper_xlib)( XFontSet,const char*, int, XRectangle*, XRectangle*, int, int*, XRectangle*, XRectangle*);
-extern void (*XmbDrawText_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, XmbTextItem*, int);
-extern void (*XwcDrawText_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, XwcTextItem*, int);
-extern void (*Xutf8DrawText_dylibloader_wrapper_xlib)( Display*, Drawable, GC, int, int, XmbTextItem*, int);
-extern void (*XmbDrawString_dylibloader_wrapper_xlib)( Display*, Drawable, XFontSet, GC, int, int,const char*, int);
-extern void (*XwcDrawString_dylibloader_wrapper_xlib)( Display*, Drawable, XFontSet, GC, int, int,const wchar_t*, int);
-extern void (*Xutf8DrawString_dylibloader_wrapper_xlib)( Display*, Drawable, XFontSet, GC, int, int,const char*, int);
-extern void (*XmbDrawImageString_dylibloader_wrapper_xlib)( Display*, Drawable, XFontSet, GC, int, int,const char*, int);
-extern void (*XwcDrawImageString_dylibloader_wrapper_xlib)( Display*, Drawable, XFontSet, GC, int, int,const wchar_t*, int);
-extern void (*Xutf8DrawImageString_dylibloader_wrapper_xlib)( Display*, Drawable, XFontSet, GC, int, int,const char*, int);
-extern XIM (*XOpenIM_dylibloader_wrapper_xlib)( Display*,struct _XrmHashBucketRec*, char*, char*);
-extern int (*XCloseIM_dylibloader_wrapper_xlib)( XIM);
-extern char* (*XGetIMValues_dylibloader_wrapper_xlib)( XIM,...);
-extern char* (*XSetIMValues_dylibloader_wrapper_xlib)( XIM,...);
-extern Display* (*XDisplayOfIM_dylibloader_wrapper_xlib)( XIM);
-extern char* (*XLocaleOfIM_dylibloader_wrapper_xlib)( XIM);
-extern XIC (*XCreateIC_dylibloader_wrapper_xlib)( XIM,...);
-extern void (*XDestroyIC_dylibloader_wrapper_xlib)( XIC);
-extern void (*XSetICFocus_dylibloader_wrapper_xlib)( XIC);
-extern void (*XUnsetICFocus_dylibloader_wrapper_xlib)( XIC);
-extern wchar_t* (*XwcResetIC_dylibloader_wrapper_xlib)( XIC);
-extern char* (*XmbResetIC_dylibloader_wrapper_xlib)( XIC);
-extern char* (*Xutf8ResetIC_dylibloader_wrapper_xlib)( XIC);
-extern char* (*XSetICValues_dylibloader_wrapper_xlib)( XIC,...);
-extern char* (*XGetICValues_dylibloader_wrapper_xlib)( XIC,...);
-extern XIM (*XIMOfIC_dylibloader_wrapper_xlib)( XIC);
-extern int (*XFilterEvent_dylibloader_wrapper_xlib)( XEvent*, Window);
-extern int (*XmbLookupString_dylibloader_wrapper_xlib)( XIC, XKeyPressedEvent*, char*, int, KeySym*, int*);
-extern int (*XwcLookupString_dylibloader_wrapper_xlib)( XIC, XKeyPressedEvent*, wchar_t*, int, KeySym*, int*);
-extern int (*Xutf8LookupString_dylibloader_wrapper_xlib)( XIC, XKeyPressedEvent*, char*, int, KeySym*, int*);
-extern XVaNestedList (*XVaCreateNestedList_dylibloader_wrapper_xlib)( int,...);
-extern int (*XRegisterIMInstantiateCallback_dylibloader_wrapper_xlib)( Display*,struct _XrmHashBucketRec*, char*, char*, XIDProc, XPointer);
-extern int (*XUnregisterIMInstantiateCallback_dylibloader_wrapper_xlib)( Display*,struct _XrmHashBucketRec*, char*, char*, XIDProc, XPointer);
-extern int (*XInternalConnectionNumbers_dylibloader_wrapper_xlib)( Display*, int**, int*);
-extern void (*XProcessInternalConnection_dylibloader_wrapper_xlib)( Display*, int);
-extern int (*XAddConnectionWatch_dylibloader_wrapper_xlib)( Display*, XConnectionWatchProc, XPointer);
-extern void (*XRemoveConnectionWatch_dylibloader_wrapper_xlib)( Display*, XConnectionWatchProc, XPointer);
-extern void (*XSetAuthorization_dylibloader_wrapper_xlib)( char*, int, char*, int);
-extern int (*_Xmbtowc_dylibloader_wrapper_xlib)( wchar_t*, char*, int);
-extern int (*_Xwctomb_dylibloader_wrapper_xlib)( char*, wchar_t);
-extern int (*XGetEventData_dylibloader_wrapper_xlib)( Display*, XGenericEventCookie*);
-extern void (*XFreeEventData_dylibloader_wrapper_xlib)( Display*, XGenericEventCookie*);
-extern XClassHint* (*XAllocClassHint_dylibloader_wrapper_xlib)( void);
-extern XIconSize* (*XAllocIconSize_dylibloader_wrapper_xlib)( void);
-extern XSizeHints* (*XAllocSizeHints_dylibloader_wrapper_xlib)( void);
-extern XStandardColormap* (*XAllocStandardColormap_dylibloader_wrapper_xlib)( void);
-extern XWMHints* (*XAllocWMHints_dylibloader_wrapper_xlib)( void);
-extern int (*XClipBox_dylibloader_wrapper_xlib)( Region, XRectangle*);
-extern Region (*XCreateRegion_dylibloader_wrapper_xlib)( void);
-extern const char* (*XDefaultString_dylibloader_wrapper_xlib)( void);
-extern int (*XDeleteContext_dylibloader_wrapper_xlib)( Display*, XID, XContext);
-extern int (*XDestroyRegion_dylibloader_wrapper_xlib)( Region);
-extern int (*XEmptyRegion_dylibloader_wrapper_xlib)( Region);
-extern int (*XEqualRegion_dylibloader_wrapper_xlib)( Region, Region);
-extern int (*XFindContext_dylibloader_wrapper_xlib)( Display*, XID, XContext, XPointer*);
-extern int (*XGetClassHint_dylibloader_wrapper_xlib)( Display*, Window, XClassHint*);
-extern int (*XGetIconSizes_dylibloader_wrapper_xlib)( Display*, Window, XIconSize**, int*);
-extern int (*XGetNormalHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*);
-extern int (*XGetRGBColormaps_dylibloader_wrapper_xlib)( Display*, Window, XStandardColormap**, int*, Atom);
-extern int (*XGetSizeHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*, Atom);
-extern int (*XGetStandardColormap_dylibloader_wrapper_xlib)( Display*, Window, XStandardColormap*, Atom);
-extern int (*XGetTextProperty_dylibloader_wrapper_xlib)( Display*, Window, XTextProperty*, Atom);
-extern XVisualInfo* (*XGetVisualInfo_dylibloader_wrapper_xlib)( Display*, long, XVisualInfo*, int*);
-extern int (*XGetWMClientMachine_dylibloader_wrapper_xlib)( Display*, Window, XTextProperty*);
-extern XWMHints* (*XGetWMHints_dylibloader_wrapper_xlib)( Display*, Window);
-extern int (*XGetWMIconName_dylibloader_wrapper_xlib)( Display*, Window, XTextProperty*);
-extern int (*XGetWMName_dylibloader_wrapper_xlib)( Display*, Window, XTextProperty*);
-extern int (*XGetWMNormalHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*, long*);
-extern int (*XGetWMSizeHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*, long*, Atom);
-extern int (*XGetZoomHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*);
-extern int (*XIntersectRegion_dylibloader_wrapper_xlib)( Region, Region, Region);
-extern void (*XConvertCase_dylibloader_wrapper_xlib)( KeySym, KeySym*, KeySym*);
-extern int (*XLookupString_dylibloader_wrapper_xlib)( XKeyEvent*, char*, int, KeySym*, XComposeStatus*);
-extern int (*XMatchVisualInfo_dylibloader_wrapper_xlib)( Display*, int, int, int, XVisualInfo*);
-extern int (*XOffsetRegion_dylibloader_wrapper_xlib)( Region, int, int);
-extern int (*XPointInRegion_dylibloader_wrapper_xlib)( Region, int, int);
-extern Region (*XPolygonRegion_dylibloader_wrapper_xlib)( XPoint*, int, int);
-extern int (*XRectInRegion_dylibloader_wrapper_xlib)( Region, int, int, unsigned int, unsigned int);
-extern int (*XSaveContext_dylibloader_wrapper_xlib)( Display*, XID, XContext,const char*);
-extern int (*XSetClassHint_dylibloader_wrapper_xlib)( Display*, Window, XClassHint*);
-extern int (*XSetIconSizes_dylibloader_wrapper_xlib)( Display*, Window, XIconSize*, int);
-extern int (*XSetNormalHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*);
-extern void (*XSetRGBColormaps_dylibloader_wrapper_xlib)( Display*, Window, XStandardColormap*, int, Atom);
-extern int (*XSetSizeHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*, Atom);
-extern int (*XSetStandardProperties_dylibloader_wrapper_xlib)( Display*, Window,const char*,const char*, Pixmap, char**, int, XSizeHints*);
-extern void (*XSetTextProperty_dylibloader_wrapper_xlib)( Display*, Window, XTextProperty*, Atom);
-extern void (*XSetWMClientMachine_dylibloader_wrapper_xlib)( Display*, Window, XTextProperty*);
-extern int (*XSetWMHints_dylibloader_wrapper_xlib)( Display*, Window, XWMHints*);
-extern void (*XSetWMIconName_dylibloader_wrapper_xlib)( Display*, Window, XTextProperty*);
-extern void (*XSetWMName_dylibloader_wrapper_xlib)( Display*, Window, XTextProperty*);
-extern void (*XSetWMNormalHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*);
-extern void (*XSetWMProperties_dylibloader_wrapper_xlib)( Display*, Window, XTextProperty*, XTextProperty*, char**, int, XSizeHints*, XWMHints*, XClassHint*);
-extern void (*XmbSetWMProperties_dylibloader_wrapper_xlib)( Display*, Window,const char*,const char*, char**, int, XSizeHints*, XWMHints*, XClassHint*);
-extern void (*Xutf8SetWMProperties_dylibloader_wrapper_xlib)( Display*, Window,const char*,const char*, char**, int, XSizeHints*, XWMHints*, XClassHint*);
-extern void (*XSetWMSizeHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*, Atom);
-extern int (*XSetRegion_dylibloader_wrapper_xlib)( Display*, GC, Region);
-extern void (*XSetStandardColormap_dylibloader_wrapper_xlib)( Display*, Window, XStandardColormap*, Atom);
-extern int (*XSetZoomHints_dylibloader_wrapper_xlib)( Display*, Window, XSizeHints*);
-extern int (*XShrinkRegion_dylibloader_wrapper_xlib)( Region, int, int);
-extern int (*XStringListToTextProperty_dylibloader_wrapper_xlib)( char**, int, XTextProperty*);
-extern int (*XSubtractRegion_dylibloader_wrapper_xlib)( Region, Region, Region);
-extern int (*XmbTextListToTextProperty_dylibloader_wrapper_xlib)( Display*, char**, int, XICCEncodingStyle, XTextProperty*);
-extern int (*XwcTextListToTextProperty_dylibloader_wrapper_xlib)( Display*, wchar_t**, int, XICCEncodingStyle, XTextProperty*);
-extern int (*Xutf8TextListToTextProperty_dylibloader_wrapper_xlib)( Display*, char**, int, XICCEncodingStyle, XTextProperty*);
-extern void (*XwcFreeStringList_dylibloader_wrapper_xlib)( wchar_t**);
-extern int (*XTextPropertyToStringList_dylibloader_wrapper_xlib)( XTextProperty*, char***, int*);
-extern int (*XmbTextPropertyToTextList_dylibloader_wrapper_xlib)( Display*,const XTextProperty*, char***, int*);
-extern int (*XwcTextPropertyToTextList_dylibloader_wrapper_xlib)( Display*,const XTextProperty*, wchar_t***, int*);
-extern int (*Xutf8TextPropertyToTextList_dylibloader_wrapper_xlib)( Display*,const XTextProperty*, char***, int*);
-extern int (*XUnionRectWithRegion_dylibloader_wrapper_xlib)( XRectangle*, Region, Region);
-extern int (*XUnionRegion_dylibloader_wrapper_xlib)( Region, Region, Region);
-extern int (*XWMGeometry_dylibloader_wrapper_xlib)( Display*, int,const char*,const char*, unsigned int, XSizeHints*, int*, int*, int*, int*, int*);
-extern int (*XXorRegion_dylibloader_wrapper_xlib)( Region, Region, Region);
-extern int (*XkbIgnoreExtension_dylibloader_wrapper_xlib)( int);
-extern Display* (*XkbOpenDisplay_dylibloader_wrapper_xlib)( char*, int*, int*, int*, int*, int*);
-extern int (*XkbQueryExtension_dylibloader_wrapper_xlib)( Display*, int*, int*, int*, int*, int*);
-extern int (*XkbUseExtension_dylibloader_wrapper_xlib)( Display*, int*, int*);
-extern int (*XkbLibraryVersion_dylibloader_wrapper_xlib)( int*, int*);
-extern unsigned int (*XkbSetXlibControls_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int);
-extern unsigned int (*XkbGetXlibControls_dylibloader_wrapper_xlib)( Display*);
-extern unsigned int (*XkbXlibControlsImplemented_dylibloader_wrapper_xlib)( void);
-extern void (*XkbSetAtomFuncs_dylibloader_wrapper_xlib)( XkbInternAtomFunc, XkbGetAtomNameFunc);
-extern KeySym (*XkbKeycodeToKeysym_dylibloader_wrapper_xlib)( Display*, KeyCode, int, int);
-extern unsigned int (*XkbKeysymToModifiers_dylibloader_wrapper_xlib)( Display*, KeySym);
-extern int (*XkbLookupKeySym_dylibloader_wrapper_xlib)( Display*, KeyCode, unsigned int, unsigned int*, KeySym*);
-extern int (*XkbLookupKeyBinding_dylibloader_wrapper_xlib)( Display*, KeySym, unsigned int, char*, int, int*);
-extern int (*XkbTranslateKeyCode_dylibloader_wrapper_xlib)( XkbDescPtr, KeyCode, unsigned int, unsigned int*, KeySym*);
-extern int (*XkbTranslateKeySym_dylibloader_wrapper_xlib)( Display*, KeySym*, unsigned int, char*, int, int*);
-extern int (*XkbSetAutoRepeatRate_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int);
-extern int (*XkbGetAutoRepeatRate_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int*, unsigned int*);
-extern int (*XkbChangeEnabledControls_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int);
-extern int (*XkbDeviceBell_dylibloader_wrapper_xlib)( Display*, Window, int, int, int, int, Atom);
-extern int (*XkbForceDeviceBell_dylibloader_wrapper_xlib)( Display*, int, int, int, int);
-extern int (*XkbDeviceBellEvent_dylibloader_wrapper_xlib)( Display*, Window, int, int, int, int, Atom);
-extern int (*XkbBell_dylibloader_wrapper_xlib)( Display*, Window, int, Atom);
-extern int (*XkbForceBell_dylibloader_wrapper_xlib)( Display*, int);
-extern int (*XkbBellEvent_dylibloader_wrapper_xlib)( Display*, Window, int, Atom);
-extern int (*XkbSelectEvents_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int);
-extern int (*XkbSelectEventDetails_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned long, unsigned long);
-extern void (*XkbNoteMapChanges_dylibloader_wrapper_xlib)( XkbMapChangesPtr, XkbMapNotifyEvent*, unsigned int);
-extern void (*XkbNoteNameChanges_dylibloader_wrapper_xlib)( XkbNameChangesPtr, XkbNamesNotifyEvent*, unsigned int);
-extern int (*XkbGetIndicatorState_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int*);
-extern int (*XkbGetIndicatorMap_dylibloader_wrapper_xlib)( Display*, unsigned long, XkbDescPtr);
-extern int (*XkbSetIndicatorMap_dylibloader_wrapper_xlib)( Display*, unsigned long, XkbDescPtr);
-extern int (*XkbGetNamedIndicator_dylibloader_wrapper_xlib)( Display*, Atom, int*, int*, XkbIndicatorMapPtr, int*);
-extern int (*XkbGetNamedDeviceIndicator_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int, Atom, int*, int*, XkbIndicatorMapPtr, int*);
-extern int (*XkbSetNamedIndicator_dylibloader_wrapper_xlib)( Display*, Atom, int, int, int, XkbIndicatorMapPtr);
-extern int (*XkbSetNamedDeviceIndicator_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int, Atom, int, int, int, XkbIndicatorMapPtr);
-extern int (*XkbLockModifiers_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int);
-extern int (*XkbLatchModifiers_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int);
-extern int (*XkbLockGroup_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int);
-extern int (*XkbLatchGroup_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int);
-extern int (*XkbSetServerInternalMods_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int);
-extern int (*XkbSetIgnoreLockMods_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int);
-extern int (*XkbVirtualModsToReal_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, unsigned int*);
-extern int (*XkbComputeEffectiveMap_dylibloader_wrapper_xlib)( XkbDescPtr, XkbKeyTypePtr, unsigned char*);
-extern int (*XkbInitCanonicalKeyTypes_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, int);
-extern XkbDescPtr (*XkbAllocKeyboard_dylibloader_wrapper_xlib)( void);
-extern void (*XkbFreeKeyboard_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, int);
-extern int (*XkbAllocClientMap_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, unsigned int);
-extern int (*XkbAllocServerMap_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, unsigned int);
-extern void (*XkbFreeClientMap_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, int);
-extern void (*XkbFreeServerMap_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, int);
-extern XkbKeyTypePtr (*XkbAddKeyType_dylibloader_wrapper_xlib)( XkbDescPtr, Atom, int, int, int);
-extern int (*XkbAllocIndicatorMaps_dylibloader_wrapper_xlib)( XkbDescPtr);
-extern void (*XkbFreeIndicatorMaps_dylibloader_wrapper_xlib)( XkbDescPtr);
-extern XkbDescPtr (*XkbGetMap_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int);
-extern int (*XkbGetUpdatedMap_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbDescPtr);
-extern int (*XkbGetMapChanges_dylibloader_wrapper_xlib)( Display*, XkbDescPtr, XkbMapChangesPtr);
-extern int (*XkbRefreshKeyboardMapping_dylibloader_wrapper_xlib)( XkbMapNotifyEvent*);
-extern int (*XkbGetKeyTypes_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, XkbDescPtr);
-extern int (*XkbGetKeySyms_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, XkbDescPtr);
-extern int (*XkbGetKeyActions_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, XkbDescPtr);
-extern int (*XkbGetKeyBehaviors_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, XkbDescPtr);
-extern int (*XkbGetVirtualMods_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbDescPtr);
-extern int (*XkbGetKeyExplicitComponents_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, XkbDescPtr);
-extern int (*XkbGetKeyModifierMap_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, XkbDescPtr);
-extern int (*XkbGetKeyVirtualModMap_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, XkbDescPtr);
-extern int (*XkbAllocControls_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int);
-extern void (*XkbFreeControls_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, int);
-extern int (*XkbGetControls_dylibloader_wrapper_xlib)( Display*, unsigned long, XkbDescPtr);
-extern int (*XkbSetControls_dylibloader_wrapper_xlib)( Display*, unsigned long, XkbDescPtr);
-extern void (*XkbNoteControlsChanges_dylibloader_wrapper_xlib)( XkbControlsChangesPtr, XkbControlsNotifyEvent*, unsigned int);
-extern int (*XkbAllocCompatMap_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, unsigned int);
-extern void (*XkbFreeCompatMap_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, int);
-extern int (*XkbGetCompatMap_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbDescPtr);
-extern int (*XkbSetCompatMap_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbDescPtr, int);
-extern int (*XkbAllocNames_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, int, int);
-extern int (*XkbGetNames_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbDescPtr);
-extern int (*XkbSetNames_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int, XkbDescPtr);
-extern int (*XkbChangeNames_dylibloader_wrapper_xlib)( Display*, XkbDescPtr, XkbNameChangesPtr);
-extern void (*XkbFreeNames_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, int);
-extern int (*XkbGetState_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbStatePtr);
-extern int (*XkbSetMap_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbDescPtr);
-extern int (*XkbChangeMap_dylibloader_wrapper_xlib)( Display*, XkbDescPtr, XkbMapChangesPtr);
-extern int (*XkbSetDetectableAutoRepeat_dylibloader_wrapper_xlib)( Display*, int, int*);
-extern int (*XkbGetDetectableAutoRepeat_dylibloader_wrapper_xlib)( Display*, int*);
-extern int (*XkbSetAutoResetControls_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int*, unsigned int*);
-extern int (*XkbGetAutoResetControls_dylibloader_wrapper_xlib)( Display*, unsigned int*, unsigned int*);
-extern int (*XkbSetPerClientControls_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int*);
-extern int (*XkbGetPerClientControls_dylibloader_wrapper_xlib)( Display*, unsigned int*);
-extern int (*XkbCopyKeyType_dylibloader_wrapper_xlib)( XkbKeyTypePtr, XkbKeyTypePtr);
-extern int (*XkbCopyKeyTypes_dylibloader_wrapper_xlib)( XkbKeyTypePtr, XkbKeyTypePtr, int);
-extern int (*XkbResizeKeyType_dylibloader_wrapper_xlib)( XkbDescPtr, int, int, int, int);
-extern KeySym* (*XkbResizeKeySyms_dylibloader_wrapper_xlib)( XkbDescPtr, int, int);
-extern XkbAction* (*XkbResizeKeyActions_dylibloader_wrapper_xlib)( XkbDescPtr, int, int);
-extern int (*XkbChangeTypesOfKey_dylibloader_wrapper_xlib)( XkbDescPtr, int, int, unsigned int, int*, XkbMapChangesPtr);
-extern int (*XkbChangeKeycodeRange_dylibloader_wrapper_xlib)( XkbDescPtr, int, int, XkbChangesPtr);
-extern XkbComponentListPtr (*XkbListComponents_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbComponentNamesPtr, int*);
-extern void (*XkbFreeComponentList_dylibloader_wrapper_xlib)( XkbComponentListPtr);
-extern XkbDescPtr (*XkbGetKeyboard_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int);
-extern XkbDescPtr (*XkbGetKeyboardByName_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbComponentNamesPtr, unsigned int, unsigned int, int);
-extern int (*XkbKeyTypesForCoreSymbols_dylibloader_wrapper_xlib)( XkbDescPtr, int, KeySym*, unsigned int, int*, KeySym*);
-extern int (*XkbApplyCompatMapToKey_dylibloader_wrapper_xlib)( XkbDescPtr, KeyCode, XkbChangesPtr);
-extern int (*XkbUpdateMapFromCore_dylibloader_wrapper_xlib)( XkbDescPtr, KeyCode, int, int, KeySym*, XkbChangesPtr);
-extern XkbDeviceLedInfoPtr (*XkbAddDeviceLedInfo_dylibloader_wrapper_xlib)( XkbDeviceInfoPtr, unsigned int, unsigned int);
-extern int (*XkbResizeDeviceButtonActions_dylibloader_wrapper_xlib)( XkbDeviceInfoPtr, unsigned int);
-extern XkbDeviceInfoPtr (*XkbAllocDeviceInfo_dylibloader_wrapper_xlib)( unsigned int, unsigned int, unsigned int);
-extern void (*XkbFreeDeviceInfo_dylibloader_wrapper_xlib)( XkbDeviceInfoPtr, unsigned int, int);
-extern void (*XkbNoteDeviceChanges_dylibloader_wrapper_xlib)( XkbDeviceChangesPtr, XkbExtensionDeviceNotifyEvent*, unsigned int);
-extern XkbDeviceInfoPtr (*XkbGetDeviceInfo_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, unsigned int, unsigned int);
-extern int (*XkbGetDeviceInfoChanges_dylibloader_wrapper_xlib)( Display*, XkbDeviceInfoPtr, XkbDeviceChangesPtr);
-extern int (*XkbGetDeviceButtonActions_dylibloader_wrapper_xlib)( Display*, XkbDeviceInfoPtr, int, unsigned int, unsigned int);
-extern int (*XkbGetDeviceLedInfo_dylibloader_wrapper_xlib)( Display*, XkbDeviceInfoPtr, unsigned int, unsigned int, unsigned int);
-extern int (*XkbSetDeviceInfo_dylibloader_wrapper_xlib)( Display*, unsigned int, XkbDeviceInfoPtr);
-extern int (*XkbChangeDeviceInfo_dylibloader_wrapper_xlib)( Display*, XkbDeviceInfoPtr, XkbDeviceChangesPtr);
-extern int (*XkbSetDeviceLedInfo_dylibloader_wrapper_xlib)( Display*, XkbDeviceInfoPtr, unsigned int, unsigned int, unsigned int);
-extern int (*XkbSetDeviceButtonActions_dylibloader_wrapper_xlib)( Display*, XkbDeviceInfoPtr, unsigned int, unsigned int);
-extern char (*XkbToControl_dylibloader_wrapper_xlib)( char);
-extern int (*XkbSetDebuggingFlags_dylibloader_wrapper_xlib)( Display*, unsigned int, unsigned int, char*, unsigned int, unsigned int, unsigned int*, unsigned int*);
-extern int (*XkbApplyVirtualModChanges_dylibloader_wrapper_xlib)( XkbDescPtr, unsigned int, XkbChangesPtr);
-extern int (*XkbUpdateActionVirtualMods_dylibloader_wrapper_xlib)( XkbDescPtr, XkbAction*, unsigned int);
-extern void (*XkbUpdateKeyTypeVirtualMods_dylibloader_wrapper_xlib)( XkbDescPtr, XkbKeyTypePtr, unsigned int, XkbChangesPtr);
+extern int (*_Xmblen_dylibloader_wrapper_xlib)(char *, int);
+extern XFontStruct *(*XLoadQueryFont_dylibloader_wrapper_xlib)(Display *, const char *);
+extern XFontStruct *(*XQueryFont_dylibloader_wrapper_xlib)(Display *, XID);
+extern XTimeCoord *(*XGetMotionEvents_dylibloader_wrapper_xlib)(Display *, Window, Time, Time, int *);
+extern XModifierKeymap *(*XDeleteModifiermapEntry_dylibloader_wrapper_xlib)(XModifierKeymap *, KeyCode, int);
+extern XModifierKeymap *(*XGetModifierMapping_dylibloader_wrapper_xlib)(Display *);
+extern XModifierKeymap *(*XInsertModifiermapEntry_dylibloader_wrapper_xlib)(XModifierKeymap *, KeyCode, int);
+extern XModifierKeymap *(*XNewModifiermap_dylibloader_wrapper_xlib)(int);
+extern XImage *(*XCreateImage_dylibloader_wrapper_xlib)(Display *, Visual *, unsigned int, int, int, char *, unsigned int, unsigned int, int, int);
+extern int (*XInitImage_dylibloader_wrapper_xlib)(XImage *);
+extern XImage *(*XGetImage_dylibloader_wrapper_xlib)(Display *, Drawable, int, int, unsigned int, unsigned int, unsigned long, int);
+extern XImage *(*XGetSubImage_dylibloader_wrapper_xlib)(Display *, Drawable, int, int, unsigned int, unsigned int, unsigned long, int, XImage *, int, int);
+extern Display *(*XOpenDisplay_dylibloader_wrapper_xlib)(const char *);
+extern void (*XrmInitialize_dylibloader_wrapper_xlib)(void);
+extern char *(*XFetchBytes_dylibloader_wrapper_xlib)(Display *, int *);
+extern char *(*XFetchBuffer_dylibloader_wrapper_xlib)(Display *, int *, int);
+extern char *(*XGetAtomName_dylibloader_wrapper_xlib)(Display *, Atom);
+extern int (*XGetAtomNames_dylibloader_wrapper_xlib)(Display *, Atom *, int, char **);
+extern char *(*XGetDefault_dylibloader_wrapper_xlib)(Display *, const char *, const char *);
+extern char *(*XDisplayName_dylibloader_wrapper_xlib)(const char *);
+extern char *(*XKeysymToString_dylibloader_wrapper_xlib)(KeySym);
+extern int (*(*XSynchronize_dylibloader_wrapper_xlib)(Display *, int))(Display *);
+extern int (*(*XSetAfterFunction_dylibloader_wrapper_xlib)(Display *, int (*)(Display *)))(Display *);
+extern Atom (*XInternAtom_dylibloader_wrapper_xlib)(Display *, const char *, int);
+extern int (*XInternAtoms_dylibloader_wrapper_xlib)(Display *, char **, int, int, Atom *);
+extern Colormap (*XCopyColormapAndFree_dylibloader_wrapper_xlib)(Display *, Colormap);
+extern Colormap (*XCreateColormap_dylibloader_wrapper_xlib)(Display *, Window, Visual *, int);
+extern Cursor (*XCreatePixmapCursor_dylibloader_wrapper_xlib)(Display *, Pixmap, Pixmap, XColor *, XColor *, unsigned int, unsigned int);
+extern Cursor (*XCreateGlyphCursor_dylibloader_wrapper_xlib)(Display *, Font, Font, unsigned int, unsigned int, const XColor *, const XColor *);
+extern Cursor (*XCreateFontCursor_dylibloader_wrapper_xlib)(Display *, unsigned int);
+extern Font (*XLoadFont_dylibloader_wrapper_xlib)(Display *, const char *);
+extern GC (*XCreateGC_dylibloader_wrapper_xlib)(Display *, Drawable, unsigned long, XGCValues *);
+extern GContext (*XGContextFromGC_dylibloader_wrapper_xlib)(GC);
+extern void (*XFlushGC_dylibloader_wrapper_xlib)(Display *, GC);
+extern Pixmap (*XCreatePixmap_dylibloader_wrapper_xlib)(Display *, Drawable, unsigned int, unsigned int, unsigned int);
+extern Pixmap (*XCreateBitmapFromData_dylibloader_wrapper_xlib)(Display *, Drawable, const char *, unsigned int, unsigned int);
+extern Pixmap (*XCreatePixmapFromBitmapData_dylibloader_wrapper_xlib)(Display *, Drawable, char *, unsigned int, unsigned int, unsigned long, unsigned long, unsigned int);
+extern Window (*XCreateSimpleWindow_dylibloader_wrapper_xlib)(Display *, Window, int, int, unsigned int, unsigned int, unsigned int, unsigned long, unsigned long);
+extern Window (*XGetSelectionOwner_dylibloader_wrapper_xlib)(Display *, Atom);
+extern Window (*XCreateWindow_dylibloader_wrapper_xlib)(Display *, Window, int, int, unsigned int, unsigned int, unsigned int, int, unsigned int, Visual *, unsigned long, XSetWindowAttributes *);
+extern Colormap *(*XListInstalledColormaps_dylibloader_wrapper_xlib)(Display *, Window, int *);
+extern char **(*XListFonts_dylibloader_wrapper_xlib)(Display *, const char *, int, int *);
+extern char **(*XListFontsWithInfo_dylibloader_wrapper_xlib)(Display *, const char *, int, int *, XFontStruct **);
+extern char **(*XGetFontPath_dylibloader_wrapper_xlib)(Display *, int *);
+extern char **(*XListExtensions_dylibloader_wrapper_xlib)(Display *, int *);
+extern Atom *(*XListProperties_dylibloader_wrapper_xlib)(Display *, Window, int *);
+extern XHostAddress *(*XListHosts_dylibloader_wrapper_xlib)(Display *, int *, int *);
+extern KeySym (*XKeycodeToKeysym_dylibloader_wrapper_xlib)(Display *, KeyCode, int);
+extern KeySym (*XLookupKeysym_dylibloader_wrapper_xlib)(XKeyEvent *, int);
+extern KeySym *(*XGetKeyboardMapping_dylibloader_wrapper_xlib)(Display *, KeyCode, int, int *);
+extern KeySym (*XStringToKeysym_dylibloader_wrapper_xlib)(const char *);
+extern long (*XMaxRequestSize_dylibloader_wrapper_xlib)(Display *);
+extern long (*XExtendedMaxRequestSize_dylibloader_wrapper_xlib)(Display *);
+extern char *(*XResourceManagerString_dylibloader_wrapper_xlib)(Display *);
+extern char *(*XScreenResourceString_dylibloader_wrapper_xlib)(Screen *);
+extern unsigned long (*XDisplayMotionBufferSize_dylibloader_wrapper_xlib)(Display *);
+extern VisualID (*XVisualIDFromVisual_dylibloader_wrapper_xlib)(Visual *);
+extern int (*XInitThreads_dylibloader_wrapper_xlib)(void);
+extern void (*XLockDisplay_dylibloader_wrapper_xlib)(Display *);
+extern void (*XUnlockDisplay_dylibloader_wrapper_xlib)(Display *);
+extern XExtCodes *(*XInitExtension_dylibloader_wrapper_xlib)(Display *, const char *);
+extern XExtCodes *(*XAddExtension_dylibloader_wrapper_xlib)(Display *);
+extern XExtData *(*XFindOnExtensionList_dylibloader_wrapper_xlib)(XExtData **, int);
+extern XExtData **(*XEHeadOfExtensionList_dylibloader_wrapper_xlib)(XEDataObject);
+extern Window (*XRootWindow_dylibloader_wrapper_xlib)(Display *, int);
+extern Window (*XDefaultRootWindow_dylibloader_wrapper_xlib)(Display *);
+extern Window (*XRootWindowOfScreen_dylibloader_wrapper_xlib)(Screen *);
+extern Visual *(*XDefaultVisual_dylibloader_wrapper_xlib)(Display *, int);
+extern Visual *(*XDefaultVisualOfScreen_dylibloader_wrapper_xlib)(Screen *);
+extern GC (*XDefaultGC_dylibloader_wrapper_xlib)(Display *, int);
+extern GC (*XDefaultGCOfScreen_dylibloader_wrapper_xlib)(Screen *);
+extern unsigned long (*XBlackPixel_dylibloader_wrapper_xlib)(Display *, int);
+extern unsigned long (*XWhitePixel_dylibloader_wrapper_xlib)(Display *, int);
+extern unsigned long (*XAllPlanes_dylibloader_wrapper_xlib)(void);
+extern unsigned long (*XBlackPixelOfScreen_dylibloader_wrapper_xlib)(Screen *);
+extern unsigned long (*XWhitePixelOfScreen_dylibloader_wrapper_xlib)(Screen *);
+extern unsigned long (*XNextRequest_dylibloader_wrapper_xlib)(Display *);
+extern unsigned long (*XLastKnownRequestProcessed_dylibloader_wrapper_xlib)(Display *);
+extern char *(*XServerVendor_dylibloader_wrapper_xlib)(Display *);
+extern char *(*XDisplayString_dylibloader_wrapper_xlib)(Display *);
+extern Colormap (*XDefaultColormap_dylibloader_wrapper_xlib)(Display *, int);
+extern Colormap (*XDefaultColormapOfScreen_dylibloader_wrapper_xlib)(Screen *);
+extern Display *(*XDisplayOfScreen_dylibloader_wrapper_xlib)(Screen *);
+extern Screen *(*XScreenOfDisplay_dylibloader_wrapper_xlib)(Display *, int);
+extern Screen *(*XDefaultScreenOfDisplay_dylibloader_wrapper_xlib)(Display *);
+extern long (*XEventMaskOfScreen_dylibloader_wrapper_xlib)(Screen *);
+extern int (*XScreenNumberOfScreen_dylibloader_wrapper_xlib)(Screen *);
+extern XErrorHandler (*XSetErrorHandler_dylibloader_wrapper_xlib)(XErrorHandler);
+extern XIOErrorHandler (*XSetIOErrorHandler_dylibloader_wrapper_xlib)(XIOErrorHandler);
+extern void (*XSetIOErrorExitHandler_dylibloader_wrapper_xlib)(Display *, XIOErrorExitHandler, void *);
+extern XPixmapFormatValues *(*XListPixmapFormats_dylibloader_wrapper_xlib)(Display *, int *);
+extern int *(*XListDepths_dylibloader_wrapper_xlib)(Display *, int, int *);
+extern int (*XReconfigureWMWindow_dylibloader_wrapper_xlib)(Display *, Window, int, unsigned int, XWindowChanges *);
+extern int (*XGetWMProtocols_dylibloader_wrapper_xlib)(Display *, Window, Atom **, int *);
+extern int (*XSetWMProtocols_dylibloader_wrapper_xlib)(Display *, Window, Atom *, int);
+extern int (*XIconifyWindow_dylibloader_wrapper_xlib)(Display *, Window, int);
+extern int (*XWithdrawWindow_dylibloader_wrapper_xlib)(Display *, Window, int);
+extern int (*XGetCommand_dylibloader_wrapper_xlib)(Display *, Window, char ***, int *);
+extern int (*XGetWMColormapWindows_dylibloader_wrapper_xlib)(Display *, Window, Window **, int *);
+extern int (*XSetWMColormapWindows_dylibloader_wrapper_xlib)(Display *, Window, Window *, int);
+extern void (*XFreeStringList_dylibloader_wrapper_xlib)(char **);
+extern int (*XSetTransientForHint_dylibloader_wrapper_xlib)(Display *, Window, Window);
+extern int (*XActivateScreenSaver_dylibloader_wrapper_xlib)(Display *);
+extern int (*XAddHost_dylibloader_wrapper_xlib)(Display *, XHostAddress *);
+extern int (*XAddHosts_dylibloader_wrapper_xlib)(Display *, XHostAddress *, int);
+extern int (*XAddToExtensionList_dylibloader_wrapper_xlib)(struct _XExtData **, XExtData *);
+extern int (*XAddToSaveSet_dylibloader_wrapper_xlib)(Display *, Window);
+extern int (*XAllocColor_dylibloader_wrapper_xlib)(Display *, Colormap, XColor *);
+extern int (*XAllocColorCells_dylibloader_wrapper_xlib)(Display *, Colormap, int, unsigned long *, unsigned int, unsigned long *, unsigned int);
+extern int (*XAllocColorPlanes_dylibloader_wrapper_xlib)(Display *, Colormap, int, unsigned long *, int, int, int, int, unsigned long *, unsigned long *, unsigned long *);
+extern int (*XAllocNamedColor_dylibloader_wrapper_xlib)(Display *, Colormap, const char *, XColor *, XColor *);
+extern int (*XAllowEvents_dylibloader_wrapper_xlib)(Display *, int, Time);
+extern int (*XAutoRepeatOff_dylibloader_wrapper_xlib)(Display *);
+extern int (*XAutoRepeatOn_dylibloader_wrapper_xlib)(Display *);
+extern int (*XBell_dylibloader_wrapper_xlib)(Display *, int);
+extern int (*XBitmapBitOrder_dylibloader_wrapper_xlib)(Display *);
+extern int (*XBitmapPad_dylibloader_wrapper_xlib)(Display *);
+extern int (*XBitmapUnit_dylibloader_wrapper_xlib)(Display *);
+extern int (*XCellsOfScreen_dylibloader_wrapper_xlib)(Screen *);
+extern int (*XChangeActivePointerGrab_dylibloader_wrapper_xlib)(Display *, unsigned int, Cursor, Time);
+extern int (*XChangeGC_dylibloader_wrapper_xlib)(Display *, GC, unsigned long, XGCValues *);
+extern int (*XChangeKeyboardControl_dylibloader_wrapper_xlib)(Display *, unsigned long, XKeyboardControl *);
+extern int (*XChangeKeyboardMapping_dylibloader_wrapper_xlib)(Display *, int, int, KeySym *, int);
+extern int (*XChangePointerControl_dylibloader_wrapper_xlib)(Display *, int, int, int, int, int);
+extern int (*XChangeProperty_dylibloader_wrapper_xlib)(Display *, Window, Atom, Atom, int, int, const unsigned char *, int);
+extern int (*XChangeSaveSet_dylibloader_wrapper_xlib)(Display *, Window, int);
+extern int (*XChangeWindowAttributes_dylibloader_wrapper_xlib)(Display *, Window, unsigned long, XSetWindowAttributes *);
+extern int (*XCheckIfEvent_dylibloader_wrapper_xlib)(Display *, XEvent *, int (*)(Display *, XEvent *, XPointer), XPointer);
+extern int (*XCheckMaskEvent_dylibloader_wrapper_xlib)(Display *, long, XEvent *);
+extern int (*XCheckTypedEvent_dylibloader_wrapper_xlib)(Display *, int, XEvent *);
+extern int (*XCheckTypedWindowEvent_dylibloader_wrapper_xlib)(Display *, Window, int, XEvent *);
+extern int (*XCheckWindowEvent_dylibloader_wrapper_xlib)(Display *, Window, long, XEvent *);
+extern int (*XCirculateSubwindows_dylibloader_wrapper_xlib)(Display *, Window, int);
+extern int (*XCirculateSubwindowsDown_dylibloader_wrapper_xlib)(Display *, Window);
+extern int (*XCirculateSubwindowsUp_dylibloader_wrapper_xlib)(Display *, Window);
+extern int (*XClearArea_dylibloader_wrapper_xlib)(Display *, Window, int, int, unsigned int, unsigned int, int);
+extern int (*XClearWindow_dylibloader_wrapper_xlib)(Display *, Window);
+extern int (*XCloseDisplay_dylibloader_wrapper_xlib)(Display *);
+extern int (*XConfigureWindow_dylibloader_wrapper_xlib)(Display *, Window, unsigned int, XWindowChanges *);
+extern int (*XConnectionNumber_dylibloader_wrapper_xlib)(Display *);
+extern int (*XConvertSelection_dylibloader_wrapper_xlib)(Display *, Atom, Atom, Atom, Window, Time);
+extern int (*XCopyArea_dylibloader_wrapper_xlib)(Display *, Drawable, Drawable, GC, int, int, unsigned int, unsigned int, int, int);
+extern int (*XCopyGC_dylibloader_wrapper_xlib)(Display *, GC, unsigned long, GC);
+extern int (*XCopyPlane_dylibloader_wrapper_xlib)(Display *, Drawable, Drawable, GC, int, int, unsigned int, unsigned int, int, int, unsigned long);
+extern int (*XDefaultDepth_dylibloader_wrapper_xlib)(Display *, int);
+extern int (*XDefaultDepthOfScreen_dylibloader_wrapper_xlib)(Screen *);
+extern int (*XDefaultScreen_dylibloader_wrapper_xlib)(Display *);
+extern int (*XDefineCursor_dylibloader_wrapper_xlib)(Display *, Window, Cursor);
+extern int (*XDeleteProperty_dylibloader_wrapper_xlib)(Display *, Window, Atom);
+extern int (*XDestroyWindow_dylibloader_wrapper_xlib)(Display *, Window);
+extern int (*XDestroySubwindows_dylibloader_wrapper_xlib)(Display *, Window);
+extern int (*XDoesBackingStore_dylibloader_wrapper_xlib)(Screen *);
+extern int (*XDoesSaveUnders_dylibloader_wrapper_xlib)(Screen *);
+extern int (*XDisableAccessControl_dylibloader_wrapper_xlib)(Display *);
+extern int (*XDisplayCells_dylibloader_wrapper_xlib)(Display *, int);
+extern int (*XDisplayHeight_dylibloader_wrapper_xlib)(Display *, int);
+extern int (*XDisplayHeightMM_dylibloader_wrapper_xlib)(Display *, int);
+extern int (*XDisplayKeycodes_dylibloader_wrapper_xlib)(Display *, int *, int *);
+extern int (*XDisplayPlanes_dylibloader_wrapper_xlib)(Display *, int);
+extern int (*XDisplayWidth_dylibloader_wrapper_xlib)(Display *, int);
+extern int (*XDisplayWidthMM_dylibloader_wrapper_xlib)(Display *, int);
+extern int (*XDrawArc_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, unsigned int, unsigned int, int, int);
+extern int (*XDrawArcs_dylibloader_wrapper_xlib)(Display *, Drawable, GC, XArc *, int);
+extern int (*XDrawImageString_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, const char *, int);
+extern int (*XDrawImageString16_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, const XChar2b *, int);
+extern int (*XDrawLine_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, int, int);
+extern int (*XDrawLines_dylibloader_wrapper_xlib)(Display *, Drawable, GC, XPoint *, int, int);
+extern int (*XDrawPoint_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int);
+extern int (*XDrawPoints_dylibloader_wrapper_xlib)(Display *, Drawable, GC, XPoint *, int, int);
+extern int (*XDrawRectangle_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, unsigned int, unsigned int);
+extern int (*XDrawRectangles_dylibloader_wrapper_xlib)(Display *, Drawable, GC, XRectangle *, int);
+extern int (*XDrawSegments_dylibloader_wrapper_xlib)(Display *, Drawable, GC, XSegment *, int);
+extern int (*XDrawString_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, const char *, int);
+extern int (*XDrawString16_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, const XChar2b *, int);
+extern int (*XDrawText_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, XTextItem *, int);
+extern int (*XDrawText16_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, XTextItem16 *, int);
+extern int (*XEnableAccessControl_dylibloader_wrapper_xlib)(Display *);
+extern int (*XEventsQueued_dylibloader_wrapper_xlib)(Display *, int);
+extern int (*XFetchName_dylibloader_wrapper_xlib)(Display *, Window, char **);
+extern int (*XFillArc_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, unsigned int, unsigned int, int, int);
+extern int (*XFillArcs_dylibloader_wrapper_xlib)(Display *, Drawable, GC, XArc *, int);
+extern int (*XFillPolygon_dylibloader_wrapper_xlib)(Display *, Drawable, GC, XPoint *, int, int, int);
+extern int (*XFillRectangle_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, unsigned int, unsigned int);
+extern int (*XFillRectangles_dylibloader_wrapper_xlib)(Display *, Drawable, GC, XRectangle *, int);
+extern int (*XFlush_dylibloader_wrapper_xlib)(Display *);
+extern int (*XForceScreenSaver_dylibloader_wrapper_xlib)(Display *, int);
+extern int (*XFree_dylibloader_wrapper_xlib)(void *);
+extern int (*XFreeColormap_dylibloader_wrapper_xlib)(Display *, Colormap);
+extern int (*XFreeColors_dylibloader_wrapper_xlib)(Display *, Colormap, unsigned long *, int, unsigned long);
+extern int (*XFreeCursor_dylibloader_wrapper_xlib)(Display *, Cursor);
+extern int (*XFreeExtensionList_dylibloader_wrapper_xlib)(char **);
+extern int (*XFreeFont_dylibloader_wrapper_xlib)(Display *, XFontStruct *);
+extern int (*XFreeFontInfo_dylibloader_wrapper_xlib)(char **, XFontStruct *, int);
+extern int (*XFreeFontNames_dylibloader_wrapper_xlib)(char **);
+extern int (*XFreeFontPath_dylibloader_wrapper_xlib)(char **);
+extern int (*XFreeGC_dylibloader_wrapper_xlib)(Display *, GC);
+extern int (*XFreeModifiermap_dylibloader_wrapper_xlib)(XModifierKeymap *);
+extern int (*XFreePixmap_dylibloader_wrapper_xlib)(Display *, Pixmap);
+extern int (*XGeometry_dylibloader_wrapper_xlib)(Display *, int, const char *, const char *, unsigned int, unsigned int, unsigned int, int, int, int *, int *, int *, int *);
+extern int (*XGetErrorDatabaseText_dylibloader_wrapper_xlib)(Display *, const char *, const char *, const char *, char *, int);
+extern int (*XGetErrorText_dylibloader_wrapper_xlib)(Display *, int, char *, int);
+extern int (*XGetFontProperty_dylibloader_wrapper_xlib)(XFontStruct *, Atom, unsigned long *);
+extern int (*XGetGCValues_dylibloader_wrapper_xlib)(Display *, GC, unsigned long, XGCValues *);
+extern int (*XGetGeometry_dylibloader_wrapper_xlib)(Display *, Drawable, Window *, int *, int *, unsigned int *, unsigned int *, unsigned int *, unsigned int *);
+extern int (*XGetIconName_dylibloader_wrapper_xlib)(Display *, Window, char **);
+extern int (*XGetInputFocus_dylibloader_wrapper_xlib)(Display *, Window *, int *);
+extern int (*XGetKeyboardControl_dylibloader_wrapper_xlib)(Display *, XKeyboardState *);
+extern int (*XGetPointerControl_dylibloader_wrapper_xlib)(Display *, int *, int *, int *);
+extern int (*XGetPointerMapping_dylibloader_wrapper_xlib)(Display *, unsigned char *, int);
+extern int (*XGetScreenSaver_dylibloader_wrapper_xlib)(Display *, int *, int *, int *, int *);
+extern int (*XGetTransientForHint_dylibloader_wrapper_xlib)(Display *, Window, Window *);
+extern int (*XGetWindowProperty_dylibloader_wrapper_xlib)(Display *, Window, Atom, long, long, int, Atom, Atom *, int *, unsigned long *, unsigned long *, unsigned char **);
+extern int (*XGetWindowAttributes_dylibloader_wrapper_xlib)(Display *, Window, XWindowAttributes *);
+extern int (*XGrabButton_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, Window, int, unsigned int, int, int, Window, Cursor);
+extern int (*XGrabKey_dylibloader_wrapper_xlib)(Display *, int, unsigned int, Window, int, int, int);
+extern int (*XGrabKeyboard_dylibloader_wrapper_xlib)(Display *, Window, int, int, int, Time);
+extern int (*XGrabPointer_dylibloader_wrapper_xlib)(Display *, Window, int, unsigned int, int, int, Window, Cursor, Time);
+extern int (*XGrabServer_dylibloader_wrapper_xlib)(Display *);
+extern int (*XHeightMMOfScreen_dylibloader_wrapper_xlib)(Screen *);
+extern int (*XHeightOfScreen_dylibloader_wrapper_xlib)(Screen *);
+extern int (*XIfEvent_dylibloader_wrapper_xlib)(Display *, XEvent *, int (*)(Display *, XEvent *, XPointer), XPointer);
+extern int (*XImageByteOrder_dylibloader_wrapper_xlib)(Display *);
+extern int (*XInstallColormap_dylibloader_wrapper_xlib)(Display *, Colormap);
+extern KeyCode (*XKeysymToKeycode_dylibloader_wrapper_xlib)(Display *, KeySym);
+extern int (*XKillClient_dylibloader_wrapper_xlib)(Display *, XID);
+extern int (*XLookupColor_dylibloader_wrapper_xlib)(Display *, Colormap, const char *, XColor *, XColor *);
+extern int (*XLowerWindow_dylibloader_wrapper_xlib)(Display *, Window);
+extern int (*XMapRaised_dylibloader_wrapper_xlib)(Display *, Window);
+extern int (*XMapSubwindows_dylibloader_wrapper_xlib)(Display *, Window);
+extern int (*XMapWindow_dylibloader_wrapper_xlib)(Display *, Window);
+extern int (*XMaskEvent_dylibloader_wrapper_xlib)(Display *, long, XEvent *);
+extern int (*XMaxCmapsOfScreen_dylibloader_wrapper_xlib)(Screen *);
+extern int (*XMinCmapsOfScreen_dylibloader_wrapper_xlib)(Screen *);
+extern int (*XMoveResizeWindow_dylibloader_wrapper_xlib)(Display *, Window, int, int, unsigned int, unsigned int);
+extern int (*XMoveWindow_dylibloader_wrapper_xlib)(Display *, Window, int, int);
+extern int (*XNextEvent_dylibloader_wrapper_xlib)(Display *, XEvent *);
+extern int (*XNoOp_dylibloader_wrapper_xlib)(Display *);
+extern int (*XParseColor_dylibloader_wrapper_xlib)(Display *, Colormap, const char *, XColor *);
+extern int (*XParseGeometry_dylibloader_wrapper_xlib)(const char *, int *, int *, unsigned int *, unsigned int *);
+extern int (*XPeekEvent_dylibloader_wrapper_xlib)(Display *, XEvent *);
+extern int (*XPeekIfEvent_dylibloader_wrapper_xlib)(Display *, XEvent *, int (*)(Display *, XEvent *, XPointer), XPointer);
+extern int (*XPending_dylibloader_wrapper_xlib)(Display *);
+extern int (*XPlanesOfScreen_dylibloader_wrapper_xlib)(Screen *);
+extern int (*XProtocolRevision_dylibloader_wrapper_xlib)(Display *);
+extern int (*XProtocolVersion_dylibloader_wrapper_xlib)(Display *);
+extern int (*XPutBackEvent_dylibloader_wrapper_xlib)(Display *, XEvent *);
+extern int (*XPutImage_dylibloader_wrapper_xlib)(Display *, Drawable, GC, XImage *, int, int, int, int, unsigned int, unsigned int);
+extern int (*XQLength_dylibloader_wrapper_xlib)(Display *);
+extern int (*XQueryBestCursor_dylibloader_wrapper_xlib)(Display *, Drawable, unsigned int, unsigned int, unsigned int *, unsigned int *);
+extern int (*XQueryBestSize_dylibloader_wrapper_xlib)(Display *, int, Drawable, unsigned int, unsigned int, unsigned int *, unsigned int *);
+extern int (*XQueryBestStipple_dylibloader_wrapper_xlib)(Display *, Drawable, unsigned int, unsigned int, unsigned int *, unsigned int *);
+extern int (*XQueryBestTile_dylibloader_wrapper_xlib)(Display *, Drawable, unsigned int, unsigned int, unsigned int *, unsigned int *);
+extern int (*XQueryColor_dylibloader_wrapper_xlib)(Display *, Colormap, XColor *);
+extern int (*XQueryColors_dylibloader_wrapper_xlib)(Display *, Colormap, XColor *, int);
+extern int (*XQueryExtension_dylibloader_wrapper_xlib)(Display *, const char *, int *, int *, int *);
+extern int (*XQueryKeymap_dylibloader_wrapper_xlib)(Display *, char [32]);
+extern int (*XQueryPointer_dylibloader_wrapper_xlib)(Display *, Window, Window *, Window *, int *, int *, int *, int *, unsigned int *);
+extern int (*XQueryTextExtents_dylibloader_wrapper_xlib)(Display *, XID, const char *, int, int *, int *, int *, XCharStruct *);
+extern int (*XQueryTextExtents16_dylibloader_wrapper_xlib)(Display *, XID, const XChar2b *, int, int *, int *, int *, XCharStruct *);
+extern int (*XQueryTree_dylibloader_wrapper_xlib)(Display *, Window, Window *, Window *, Window **, unsigned int *);
+extern int (*XRaiseWindow_dylibloader_wrapper_xlib)(Display *, Window);
+extern int (*XReadBitmapFile_dylibloader_wrapper_xlib)(Display *, Drawable, const char *, unsigned int *, unsigned int *, Pixmap *, int *, int *);
+extern int (*XReadBitmapFileData_dylibloader_wrapper_xlib)(const char *, unsigned int *, unsigned int *, unsigned char **, int *, int *);
+extern int (*XRebindKeysym_dylibloader_wrapper_xlib)(Display *, KeySym, KeySym *, int, const unsigned char *, int);
+extern int (*XRecolorCursor_dylibloader_wrapper_xlib)(Display *, Cursor, XColor *, XColor *);
+extern int (*XRefreshKeyboardMapping_dylibloader_wrapper_xlib)(XMappingEvent *);
+extern int (*XRemoveFromSaveSet_dylibloader_wrapper_xlib)(Display *, Window);
+extern int (*XRemoveHost_dylibloader_wrapper_xlib)(Display *, XHostAddress *);
+extern int (*XRemoveHosts_dylibloader_wrapper_xlib)(Display *, XHostAddress *, int);
+extern int (*XReparentWindow_dylibloader_wrapper_xlib)(Display *, Window, Window, int, int);
+extern int (*XResetScreenSaver_dylibloader_wrapper_xlib)(Display *);
+extern int (*XResizeWindow_dylibloader_wrapper_xlib)(Display *, Window, unsigned int, unsigned int);
+extern int (*XRestackWindows_dylibloader_wrapper_xlib)(Display *, Window *, int);
+extern int (*XRotateBuffers_dylibloader_wrapper_xlib)(Display *, int);
+extern int (*XRotateWindowProperties_dylibloader_wrapper_xlib)(Display *, Window, Atom *, int, int);
+extern int (*XScreenCount_dylibloader_wrapper_xlib)(Display *);
+extern int (*XSelectInput_dylibloader_wrapper_xlib)(Display *, Window, long);
+extern int (*XSendEvent_dylibloader_wrapper_xlib)(Display *, Window, int, long, XEvent *);
+extern int (*XSetAccessControl_dylibloader_wrapper_xlib)(Display *, int);
+extern int (*XSetArcMode_dylibloader_wrapper_xlib)(Display *, GC, int);
+extern int (*XSetBackground_dylibloader_wrapper_xlib)(Display *, GC, unsigned long);
+extern int (*XSetClipMask_dylibloader_wrapper_xlib)(Display *, GC, Pixmap);
+extern int (*XSetClipOrigin_dylibloader_wrapper_xlib)(Display *, GC, int, int);
+extern int (*XSetClipRectangles_dylibloader_wrapper_xlib)(Display *, GC, int, int, XRectangle *, int, int);
+extern int (*XSetCloseDownMode_dylibloader_wrapper_xlib)(Display *, int);
+extern int (*XSetCommand_dylibloader_wrapper_xlib)(Display *, Window, char **, int);
+extern int (*XSetDashes_dylibloader_wrapper_xlib)(Display *, GC, int, const char *, int);
+extern int (*XSetFillRule_dylibloader_wrapper_xlib)(Display *, GC, int);
+extern int (*XSetFillStyle_dylibloader_wrapper_xlib)(Display *, GC, int);
+extern int (*XSetFont_dylibloader_wrapper_xlib)(Display *, GC, Font);
+extern int (*XSetFontPath_dylibloader_wrapper_xlib)(Display *, char **, int);
+extern int (*XSetForeground_dylibloader_wrapper_xlib)(Display *, GC, unsigned long);
+extern int (*XSetFunction_dylibloader_wrapper_xlib)(Display *, GC, int);
+extern int (*XSetGraphicsExposures_dylibloader_wrapper_xlib)(Display *, GC, int);
+extern int (*XSetIconName_dylibloader_wrapper_xlib)(Display *, Window, const char *);
+extern int (*XSetInputFocus_dylibloader_wrapper_xlib)(Display *, Window, int, Time);
+extern int (*XSetLineAttributes_dylibloader_wrapper_xlib)(Display *, GC, unsigned int, int, int, int);
+extern int (*XSetModifierMapping_dylibloader_wrapper_xlib)(Display *, XModifierKeymap *);
+extern int (*XSetPlaneMask_dylibloader_wrapper_xlib)(Display *, GC, unsigned long);
+extern int (*XSetPointerMapping_dylibloader_wrapper_xlib)(Display *, const unsigned char *, int);
+extern int (*XSetScreenSaver_dylibloader_wrapper_xlib)(Display *, int, int, int, int);
+extern int (*XSetSelectionOwner_dylibloader_wrapper_xlib)(Display *, Atom, Window, Time);
+extern int (*XSetState_dylibloader_wrapper_xlib)(Display *, GC, unsigned long, unsigned long, int, unsigned long);
+extern int (*XSetStipple_dylibloader_wrapper_xlib)(Display *, GC, Pixmap);
+extern int (*XSetSubwindowMode_dylibloader_wrapper_xlib)(Display *, GC, int);
+extern int (*XSetTSOrigin_dylibloader_wrapper_xlib)(Display *, GC, int, int);
+extern int (*XSetTile_dylibloader_wrapper_xlib)(Display *, GC, Pixmap);
+extern int (*XSetWindowBackground_dylibloader_wrapper_xlib)(Display *, Window, unsigned long);
+extern int (*XSetWindowBackgroundPixmap_dylibloader_wrapper_xlib)(Display *, Window, Pixmap);
+extern int (*XSetWindowBorder_dylibloader_wrapper_xlib)(Display *, Window, unsigned long);
+extern int (*XSetWindowBorderPixmap_dylibloader_wrapper_xlib)(Display *, Window, Pixmap);
+extern int (*XSetWindowBorderWidth_dylibloader_wrapper_xlib)(Display *, Window, unsigned int);
+extern int (*XSetWindowColormap_dylibloader_wrapper_xlib)(Display *, Window, Colormap);
+extern int (*XStoreBuffer_dylibloader_wrapper_xlib)(Display *, const char *, int, int);
+extern int (*XStoreBytes_dylibloader_wrapper_xlib)(Display *, const char *, int);
+extern int (*XStoreColor_dylibloader_wrapper_xlib)(Display *, Colormap, XColor *);
+extern int (*XStoreColors_dylibloader_wrapper_xlib)(Display *, Colormap, XColor *, int);
+extern int (*XStoreName_dylibloader_wrapper_xlib)(Display *, Window, const char *);
+extern int (*XStoreNamedColor_dylibloader_wrapper_xlib)(Display *, Colormap, const char *, unsigned long, int);
+extern int (*XSync_dylibloader_wrapper_xlib)(Display *, int);
+extern int (*XTextExtents_dylibloader_wrapper_xlib)(XFontStruct *, const char *, int, int *, int *, int *, XCharStruct *);
+extern int (*XTextExtents16_dylibloader_wrapper_xlib)(XFontStruct *, const XChar2b *, int, int *, int *, int *, XCharStruct *);
+extern int (*XTextWidth_dylibloader_wrapper_xlib)(XFontStruct *, const char *, int);
+extern int (*XTextWidth16_dylibloader_wrapper_xlib)(XFontStruct *, const XChar2b *, int);
+extern int (*XTranslateCoordinates_dylibloader_wrapper_xlib)(Display *, Window, Window, int, int, int *, int *, Window *);
+extern int (*XUndefineCursor_dylibloader_wrapper_xlib)(Display *, Window);
+extern int (*XUngrabButton_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, Window);
+extern int (*XUngrabKey_dylibloader_wrapper_xlib)(Display *, int, unsigned int, Window);
+extern int (*XUngrabKeyboard_dylibloader_wrapper_xlib)(Display *, Time);
+extern int (*XUngrabPointer_dylibloader_wrapper_xlib)(Display *, Time);
+extern int (*XUngrabServer_dylibloader_wrapper_xlib)(Display *);
+extern int (*XUninstallColormap_dylibloader_wrapper_xlib)(Display *, Colormap);
+extern int (*XUnloadFont_dylibloader_wrapper_xlib)(Display *, Font);
+extern int (*XUnmapSubwindows_dylibloader_wrapper_xlib)(Display *, Window);
+extern int (*XUnmapWindow_dylibloader_wrapper_xlib)(Display *, Window);
+extern int (*XVendorRelease_dylibloader_wrapper_xlib)(Display *);
+extern int (*XWarpPointer_dylibloader_wrapper_xlib)(Display *, Window, Window, int, int, unsigned int, unsigned int, int, int);
+extern int (*XWidthMMOfScreen_dylibloader_wrapper_xlib)(Screen *);
+extern int (*XWidthOfScreen_dylibloader_wrapper_xlib)(Screen *);
+extern int (*XWindowEvent_dylibloader_wrapper_xlib)(Display *, Window, long, XEvent *);
+extern int (*XWriteBitmapFile_dylibloader_wrapper_xlib)(Display *, const char *, Pixmap, unsigned int, unsigned int, int, int);
+extern int (*XSupportsLocale_dylibloader_wrapper_xlib)(void);
+extern char *(*XSetLocaleModifiers_dylibloader_wrapper_xlib)(const char *);
+extern XOM (*XOpenOM_dylibloader_wrapper_xlib)(Display *, struct _XrmHashBucketRec *, const char *, const char *);
+extern int (*XCloseOM_dylibloader_wrapper_xlib)(XOM);
+extern char *(*XSetOMValues_dylibloader_wrapper_xlib)(XOM, ...);
+extern char *(*XGetOMValues_dylibloader_wrapper_xlib)(XOM, ...);
+extern Display *(*XDisplayOfOM_dylibloader_wrapper_xlib)(XOM);
+extern char *(*XLocaleOfOM_dylibloader_wrapper_xlib)(XOM);
+extern XOC (*XCreateOC_dylibloader_wrapper_xlib)(XOM, ...);
+extern void (*XDestroyOC_dylibloader_wrapper_xlib)(XOC);
+extern XOM (*XOMOfOC_dylibloader_wrapper_xlib)(XOC);
+extern char *(*XSetOCValues_dylibloader_wrapper_xlib)(XOC, ...);
+extern char *(*XGetOCValues_dylibloader_wrapper_xlib)(XOC, ...);
+extern XFontSet (*XCreateFontSet_dylibloader_wrapper_xlib)(Display *, const char *, char ***, int *, char **);
+extern void (*XFreeFontSet_dylibloader_wrapper_xlib)(Display *, XFontSet);
+extern int (*XFontsOfFontSet_dylibloader_wrapper_xlib)(XFontSet, XFontStruct ***, char ***);
+extern char *(*XBaseFontNameListOfFontSet_dylibloader_wrapper_xlib)(XFontSet);
+extern char *(*XLocaleOfFontSet_dylibloader_wrapper_xlib)(XFontSet);
+extern int (*XContextDependentDrawing_dylibloader_wrapper_xlib)(XFontSet);
+extern int (*XDirectionalDependentDrawing_dylibloader_wrapper_xlib)(XFontSet);
+extern int (*XContextualDrawing_dylibloader_wrapper_xlib)(XFontSet);
+extern XFontSetExtents *(*XExtentsOfFontSet_dylibloader_wrapper_xlib)(XFontSet);
+extern int (*XmbTextEscapement_dylibloader_wrapper_xlib)(XFontSet, const char *, int);
+extern int (*XwcTextEscapement_dylibloader_wrapper_xlib)(XFontSet, const wchar_t *, int);
+extern int (*Xutf8TextEscapement_dylibloader_wrapper_xlib)(XFontSet, const char *, int);
+extern int (*XmbTextExtents_dylibloader_wrapper_xlib)(XFontSet, const char *, int, XRectangle *, XRectangle *);
+extern int (*XwcTextExtents_dylibloader_wrapper_xlib)(XFontSet, const wchar_t *, int, XRectangle *, XRectangle *);
+extern int (*Xutf8TextExtents_dylibloader_wrapper_xlib)(XFontSet, const char *, int, XRectangle *, XRectangle *);
+extern int (*XmbTextPerCharExtents_dylibloader_wrapper_xlib)(XFontSet, const char *, int, XRectangle *, XRectangle *, int, int *, XRectangle *, XRectangle *);
+extern int (*XwcTextPerCharExtents_dylibloader_wrapper_xlib)(XFontSet, const wchar_t *, int, XRectangle *, XRectangle *, int, int *, XRectangle *, XRectangle *);
+extern int (*Xutf8TextPerCharExtents_dylibloader_wrapper_xlib)(XFontSet, const char *, int, XRectangle *, XRectangle *, int, int *, XRectangle *, XRectangle *);
+extern void (*XmbDrawText_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, XmbTextItem *, int);
+extern void (*XwcDrawText_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, XwcTextItem *, int);
+extern void (*Xutf8DrawText_dylibloader_wrapper_xlib)(Display *, Drawable, GC, int, int, XmbTextItem *, int);
+extern void (*XmbDrawString_dylibloader_wrapper_xlib)(Display *, Drawable, XFontSet, GC, int, int, const char *, int);
+extern void (*XwcDrawString_dylibloader_wrapper_xlib)(Display *, Drawable, XFontSet, GC, int, int, const wchar_t *, int);
+extern void (*Xutf8DrawString_dylibloader_wrapper_xlib)(Display *, Drawable, XFontSet, GC, int, int, const char *, int);
+extern void (*XmbDrawImageString_dylibloader_wrapper_xlib)(Display *, Drawable, XFontSet, GC, int, int, const char *, int);
+extern void (*XwcDrawImageString_dylibloader_wrapper_xlib)(Display *, Drawable, XFontSet, GC, int, int, const wchar_t *, int);
+extern void (*Xutf8DrawImageString_dylibloader_wrapper_xlib)(Display *, Drawable, XFontSet, GC, int, int, const char *, int);
+extern XIM (*XOpenIM_dylibloader_wrapper_xlib)(Display *, struct _XrmHashBucketRec *, char *, char *);
+extern int (*XCloseIM_dylibloader_wrapper_xlib)(XIM);
+extern char *(*XGetIMValues_dylibloader_wrapper_xlib)(XIM, ...);
+extern char *(*XSetIMValues_dylibloader_wrapper_xlib)(XIM, ...);
+extern Display *(*XDisplayOfIM_dylibloader_wrapper_xlib)(XIM);
+extern char *(*XLocaleOfIM_dylibloader_wrapper_xlib)(XIM);
+extern XIC (*XCreateIC_dylibloader_wrapper_xlib)(XIM, ...);
+extern void (*XDestroyIC_dylibloader_wrapper_xlib)(XIC);
+extern void (*XSetICFocus_dylibloader_wrapper_xlib)(XIC);
+extern void (*XUnsetICFocus_dylibloader_wrapper_xlib)(XIC);
+extern wchar_t *(*XwcResetIC_dylibloader_wrapper_xlib)(XIC);
+extern char *(*XmbResetIC_dylibloader_wrapper_xlib)(XIC);
+extern char *(*Xutf8ResetIC_dylibloader_wrapper_xlib)(XIC);
+extern char *(*XSetICValues_dylibloader_wrapper_xlib)(XIC, ...);
+extern char *(*XGetICValues_dylibloader_wrapper_xlib)(XIC, ...);
+extern XIM (*XIMOfIC_dylibloader_wrapper_xlib)(XIC);
+extern int (*XFilterEvent_dylibloader_wrapper_xlib)(XEvent *, Window);
+extern int (*XmbLookupString_dylibloader_wrapper_xlib)(XIC, XKeyPressedEvent *, char *, int, KeySym *, int *);
+extern int (*XwcLookupString_dylibloader_wrapper_xlib)(XIC, XKeyPressedEvent *, wchar_t *, int, KeySym *, int *);
+extern int (*Xutf8LookupString_dylibloader_wrapper_xlib)(XIC, XKeyPressedEvent *, char *, int, KeySym *, int *);
+extern XVaNestedList (*XVaCreateNestedList_dylibloader_wrapper_xlib)(int, ...);
+extern int (*XRegisterIMInstantiateCallback_dylibloader_wrapper_xlib)(Display *, struct _XrmHashBucketRec *, char *, char *, XIDProc, XPointer);
+extern int (*XUnregisterIMInstantiateCallback_dylibloader_wrapper_xlib)(Display *, struct _XrmHashBucketRec *, char *, char *, XIDProc, XPointer);
+extern int (*XInternalConnectionNumbers_dylibloader_wrapper_xlib)(Display *, int **, int *);
+extern void (*XProcessInternalConnection_dylibloader_wrapper_xlib)(Display *, int);
+extern int (*XAddConnectionWatch_dylibloader_wrapper_xlib)(Display *, XConnectionWatchProc, XPointer);
+extern void (*XRemoveConnectionWatch_dylibloader_wrapper_xlib)(Display *, XConnectionWatchProc, XPointer);
+extern void (*XSetAuthorization_dylibloader_wrapper_xlib)(char *, int, char *, int);
+extern int (*_Xmbtowc_dylibloader_wrapper_xlib)(wchar_t *, char *, int);
+extern int (*_Xwctomb_dylibloader_wrapper_xlib)(char *, wchar_t);
+extern int (*XGetEventData_dylibloader_wrapper_xlib)(Display *, XGenericEventCookie *);
+extern void (*XFreeEventData_dylibloader_wrapper_xlib)(Display *, XGenericEventCookie *);
+extern int (*XFreeThreads_dylibloader_wrapper_xlib)(void);
+extern XClassHint *(*XAllocClassHint_dylibloader_wrapper_xlib)(void);
+extern XIconSize *(*XAllocIconSize_dylibloader_wrapper_xlib)(void);
+extern XSizeHints *(*XAllocSizeHints_dylibloader_wrapper_xlib)(void);
+extern XStandardColormap *(*XAllocStandardColormap_dylibloader_wrapper_xlib)(void);
+extern XWMHints *(*XAllocWMHints_dylibloader_wrapper_xlib)(void);
+extern int (*XClipBox_dylibloader_wrapper_xlib)(Region, XRectangle *);
+extern Region (*XCreateRegion_dylibloader_wrapper_xlib)(void);
+extern const char *(*XDefaultString_dylibloader_wrapper_xlib)(void);
+extern int (*XDeleteContext_dylibloader_wrapper_xlib)(Display *, XID, XContext);
+extern int (*XDestroyRegion_dylibloader_wrapper_xlib)(Region);
+extern int (*XEmptyRegion_dylibloader_wrapper_xlib)(Region);
+extern int (*XEqualRegion_dylibloader_wrapper_xlib)(Region, Region);
+extern int (*XFindContext_dylibloader_wrapper_xlib)(Display *, XID, XContext, XPointer *);
+extern int (*XGetClassHint_dylibloader_wrapper_xlib)(Display *, Window, XClassHint *);
+extern int (*XGetIconSizes_dylibloader_wrapper_xlib)(Display *, Window, XIconSize **, int *);
+extern int (*XGetNormalHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *);
+extern int (*XGetRGBColormaps_dylibloader_wrapper_xlib)(Display *, Window, XStandardColormap **, int *, Atom);
+extern int (*XGetSizeHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *, Atom);
+extern int (*XGetStandardColormap_dylibloader_wrapper_xlib)(Display *, Window, XStandardColormap *, Atom);
+extern int (*XGetTextProperty_dylibloader_wrapper_xlib)(Display *, Window, XTextProperty *, Atom);
+extern XVisualInfo *(*XGetVisualInfo_dylibloader_wrapper_xlib)(Display *, long, XVisualInfo *, int *);
+extern int (*XGetWMClientMachine_dylibloader_wrapper_xlib)(Display *, Window, XTextProperty *);
+extern XWMHints *(*XGetWMHints_dylibloader_wrapper_xlib)(Display *, Window);
+extern int (*XGetWMIconName_dylibloader_wrapper_xlib)(Display *, Window, XTextProperty *);
+extern int (*XGetWMName_dylibloader_wrapper_xlib)(Display *, Window, XTextProperty *);
+extern int (*XGetWMNormalHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *, long *);
+extern int (*XGetWMSizeHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *, long *, Atom);
+extern int (*XGetZoomHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *);
+extern int (*XIntersectRegion_dylibloader_wrapper_xlib)(Region, Region, Region);
+extern void (*XConvertCase_dylibloader_wrapper_xlib)(KeySym, KeySym *, KeySym *);
+extern int (*XLookupString_dylibloader_wrapper_xlib)(XKeyEvent *, char *, int, KeySym *, XComposeStatus *);
+extern int (*XMatchVisualInfo_dylibloader_wrapper_xlib)(Display *, int, int, int, XVisualInfo *);
+extern int (*XOffsetRegion_dylibloader_wrapper_xlib)(Region, int, int);
+extern int (*XPointInRegion_dylibloader_wrapper_xlib)(Region, int, int);
+extern Region (*XPolygonRegion_dylibloader_wrapper_xlib)(XPoint *, int, int);
+extern int (*XRectInRegion_dylibloader_wrapper_xlib)(Region, int, int, unsigned int, unsigned int);
+extern int (*XSaveContext_dylibloader_wrapper_xlib)(Display *, XID, XContext, const char *);
+extern int (*XSetClassHint_dylibloader_wrapper_xlib)(Display *, Window, XClassHint *);
+extern int (*XSetIconSizes_dylibloader_wrapper_xlib)(Display *, Window, XIconSize *, int);
+extern int (*XSetNormalHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *);
+extern void (*XSetRGBColormaps_dylibloader_wrapper_xlib)(Display *, Window, XStandardColormap *, int, Atom);
+extern int (*XSetSizeHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *, Atom);
+extern int (*XSetStandardProperties_dylibloader_wrapper_xlib)(Display *, Window, const char *, const char *, Pixmap, char **, int, XSizeHints *);
+extern void (*XSetTextProperty_dylibloader_wrapper_xlib)(Display *, Window, XTextProperty *, Atom);
+extern void (*XSetWMClientMachine_dylibloader_wrapper_xlib)(Display *, Window, XTextProperty *);
+extern int (*XSetWMHints_dylibloader_wrapper_xlib)(Display *, Window, XWMHints *);
+extern void (*XSetWMIconName_dylibloader_wrapper_xlib)(Display *, Window, XTextProperty *);
+extern void (*XSetWMName_dylibloader_wrapper_xlib)(Display *, Window, XTextProperty *);
+extern void (*XSetWMNormalHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *);
+extern void (*XSetWMProperties_dylibloader_wrapper_xlib)(Display *, Window, XTextProperty *, XTextProperty *, char **, int, XSizeHints *, XWMHints *, XClassHint *);
+extern void (*XmbSetWMProperties_dylibloader_wrapper_xlib)(Display *, Window, const char *, const char *, char **, int, XSizeHints *, XWMHints *, XClassHint *);
+extern void (*Xutf8SetWMProperties_dylibloader_wrapper_xlib)(Display *, Window, const char *, const char *, char **, int, XSizeHints *, XWMHints *, XClassHint *);
+extern void (*XSetWMSizeHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *, Atom);
+extern int (*XSetRegion_dylibloader_wrapper_xlib)(Display *, GC, Region);
+extern void (*XSetStandardColormap_dylibloader_wrapper_xlib)(Display *, Window, XStandardColormap *, Atom);
+extern int (*XSetZoomHints_dylibloader_wrapper_xlib)(Display *, Window, XSizeHints *);
+extern int (*XShrinkRegion_dylibloader_wrapper_xlib)(Region, int, int);
+extern int (*XStringListToTextProperty_dylibloader_wrapper_xlib)(char **, int, XTextProperty *);
+extern int (*XSubtractRegion_dylibloader_wrapper_xlib)(Region, Region, Region);
+extern int (*XmbTextListToTextProperty_dylibloader_wrapper_xlib)(Display *, char **, int, XICCEncodingStyle, XTextProperty *);
+extern int (*XwcTextListToTextProperty_dylibloader_wrapper_xlib)(Display *, wchar_t **, int, XICCEncodingStyle, XTextProperty *);
+extern int (*Xutf8TextListToTextProperty_dylibloader_wrapper_xlib)(Display *, char **, int, XICCEncodingStyle, XTextProperty *);
+extern void (*XwcFreeStringList_dylibloader_wrapper_xlib)(wchar_t **);
+extern int (*XTextPropertyToStringList_dylibloader_wrapper_xlib)(XTextProperty *, char ***, int *);
+extern int (*XmbTextPropertyToTextList_dylibloader_wrapper_xlib)(Display *, const XTextProperty *, char ***, int *);
+extern int (*XwcTextPropertyToTextList_dylibloader_wrapper_xlib)(Display *, const XTextProperty *, wchar_t ***, int *);
+extern int (*Xutf8TextPropertyToTextList_dylibloader_wrapper_xlib)(Display *, const XTextProperty *, char ***, int *);
+extern int (*XUnionRectWithRegion_dylibloader_wrapper_xlib)(XRectangle *, Region, Region);
+extern int (*XUnionRegion_dylibloader_wrapper_xlib)(Region, Region, Region);
+extern int (*XWMGeometry_dylibloader_wrapper_xlib)(Display *, int, const char *, const char *, unsigned int, XSizeHints *, int *, int *, int *, int *, int *);
+extern int (*XXorRegion_dylibloader_wrapper_xlib)(Region, Region, Region);
+extern int (*XkbIgnoreExtension_dylibloader_wrapper_xlib)(int);
+extern Display *(*XkbOpenDisplay_dylibloader_wrapper_xlib)(char *, int *, int *, int *, int *, int *);
+extern int (*XkbQueryExtension_dylibloader_wrapper_xlib)(Display *, int *, int *, int *, int *, int *);
+extern int (*XkbUseExtension_dylibloader_wrapper_xlib)(Display *, int *, int *);
+extern int (*XkbLibraryVersion_dylibloader_wrapper_xlib)(int *, int *);
+extern unsigned int (*XkbSetXlibControls_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int);
+extern unsigned int (*XkbGetXlibControls_dylibloader_wrapper_xlib)(Display *);
+extern unsigned int (*XkbXlibControlsImplemented_dylibloader_wrapper_xlib)(void);
+extern void (*XkbSetAtomFuncs_dylibloader_wrapper_xlib)(XkbInternAtomFunc, XkbGetAtomNameFunc);
+extern KeySym (*XkbKeycodeToKeysym_dylibloader_wrapper_xlib)(Display *, KeyCode, int, int);
+extern unsigned int (*XkbKeysymToModifiers_dylibloader_wrapper_xlib)(Display *, KeySym);
+extern int (*XkbLookupKeySym_dylibloader_wrapper_xlib)(Display *, KeyCode, unsigned int, unsigned int *, KeySym *);
+extern int (*XkbLookupKeyBinding_dylibloader_wrapper_xlib)(Display *, KeySym, unsigned int, char *, int, int *);
+extern int (*XkbTranslateKeyCode_dylibloader_wrapper_xlib)(XkbDescPtr, KeyCode, unsigned int, unsigned int *, KeySym *);
+extern int (*XkbTranslateKeySym_dylibloader_wrapper_xlib)(Display *, KeySym *, unsigned int, char *, int, int *);
+extern int (*XkbSetAutoRepeatRate_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int);
+extern int (*XkbGetAutoRepeatRate_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int *, unsigned int *);
+extern int (*XkbChangeEnabledControls_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int);
+extern int (*XkbDeviceBell_dylibloader_wrapper_xlib)(Display *, Window, int, int, int, int, Atom);
+extern int (*XkbForceDeviceBell_dylibloader_wrapper_xlib)(Display *, int, int, int, int);
+extern int (*XkbDeviceBellEvent_dylibloader_wrapper_xlib)(Display *, Window, int, int, int, int, Atom);
+extern int (*XkbBell_dylibloader_wrapper_xlib)(Display *, Window, int, Atom);
+extern int (*XkbForceBell_dylibloader_wrapper_xlib)(Display *, int);
+extern int (*XkbBellEvent_dylibloader_wrapper_xlib)(Display *, Window, int, Atom);
+extern int (*XkbSelectEvents_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int);
+extern int (*XkbSelectEventDetails_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned long, unsigned long);
+extern void (*XkbNoteMapChanges_dylibloader_wrapper_xlib)(XkbMapChangesPtr, XkbMapNotifyEvent *, unsigned int);
+extern void (*XkbNoteNameChanges_dylibloader_wrapper_xlib)(XkbNameChangesPtr, XkbNamesNotifyEvent *, unsigned int);
+extern int (*XkbGetIndicatorState_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int *);
+extern int (*XkbGetIndicatorMap_dylibloader_wrapper_xlib)(Display *, unsigned long, XkbDescPtr);
+extern int (*XkbSetIndicatorMap_dylibloader_wrapper_xlib)(Display *, unsigned long, XkbDescPtr);
+extern int (*XkbGetNamedIndicator_dylibloader_wrapper_xlib)(Display *, Atom, int *, int *, XkbIndicatorMapPtr, int *);
+extern int (*XkbGetNamedDeviceIndicator_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int, Atom, int *, int *, XkbIndicatorMapPtr, int *);
+extern int (*XkbSetNamedIndicator_dylibloader_wrapper_xlib)(Display *, Atom, int, int, int, XkbIndicatorMapPtr);
+extern int (*XkbSetNamedDeviceIndicator_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int, Atom, int, int, int, XkbIndicatorMapPtr);
+extern int (*XkbLockModifiers_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int);
+extern int (*XkbLatchModifiers_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int);
+extern int (*XkbLockGroup_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int);
+extern int (*XkbLatchGroup_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int);
+extern int (*XkbSetServerInternalMods_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int);
+extern int (*XkbSetIgnoreLockMods_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int);
+extern int (*XkbVirtualModsToReal_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, unsigned int *);
+extern int (*XkbComputeEffectiveMap_dylibloader_wrapper_xlib)(XkbDescPtr, XkbKeyTypePtr, unsigned char *);
+extern int (*XkbInitCanonicalKeyTypes_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, int);
+extern XkbDescPtr (*XkbAllocKeyboard_dylibloader_wrapper_xlib)(void);
+extern void (*XkbFreeKeyboard_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, int);
+extern int (*XkbAllocClientMap_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, unsigned int);
+extern int (*XkbAllocServerMap_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, unsigned int);
+extern void (*XkbFreeClientMap_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, int);
+extern void (*XkbFreeServerMap_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, int);
+extern XkbKeyTypePtr (*XkbAddKeyType_dylibloader_wrapper_xlib)(XkbDescPtr, Atom, int, int, int);
+extern int (*XkbAllocIndicatorMaps_dylibloader_wrapper_xlib)(XkbDescPtr);
+extern void (*XkbFreeIndicatorMaps_dylibloader_wrapper_xlib)(XkbDescPtr);
+extern XkbDescPtr (*XkbGetMap_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int);
+extern int (*XkbGetUpdatedMap_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbDescPtr);
+extern int (*XkbGetMapChanges_dylibloader_wrapper_xlib)(Display *, XkbDescPtr, XkbMapChangesPtr);
+extern int (*XkbRefreshKeyboardMapping_dylibloader_wrapper_xlib)(XkbMapNotifyEvent *);
+extern int (*XkbGetKeyTypes_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, XkbDescPtr);
+extern int (*XkbGetKeySyms_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, XkbDescPtr);
+extern int (*XkbGetKeyActions_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, XkbDescPtr);
+extern int (*XkbGetKeyBehaviors_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, XkbDescPtr);
+extern int (*XkbGetVirtualMods_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbDescPtr);
+extern int (*XkbGetKeyExplicitComponents_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, XkbDescPtr);
+extern int (*XkbGetKeyModifierMap_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, XkbDescPtr);
+extern int (*XkbGetKeyVirtualModMap_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, XkbDescPtr);
+extern int (*XkbAllocControls_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int);
+extern void (*XkbFreeControls_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, int);
+extern int (*XkbGetControls_dylibloader_wrapper_xlib)(Display *, unsigned long, XkbDescPtr);
+extern int (*XkbSetControls_dylibloader_wrapper_xlib)(Display *, unsigned long, XkbDescPtr);
+extern void (*XkbNoteControlsChanges_dylibloader_wrapper_xlib)(XkbControlsChangesPtr, XkbControlsNotifyEvent *, unsigned int);
+extern int (*XkbAllocCompatMap_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, unsigned int);
+extern void (*XkbFreeCompatMap_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, int);
+extern int (*XkbGetCompatMap_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbDescPtr);
+extern int (*XkbSetCompatMap_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbDescPtr, int);
+extern int (*XkbAllocNames_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, int, int);
+extern int (*XkbGetNames_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbDescPtr);
+extern int (*XkbSetNames_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int, XkbDescPtr);
+extern int (*XkbChangeNames_dylibloader_wrapper_xlib)(Display *, XkbDescPtr, XkbNameChangesPtr);
+extern void (*XkbFreeNames_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, int);
+extern int (*XkbGetState_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbStatePtr);
+extern int (*XkbSetMap_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbDescPtr);
+extern int (*XkbChangeMap_dylibloader_wrapper_xlib)(Display *, XkbDescPtr, XkbMapChangesPtr);
+extern int (*XkbSetDetectableAutoRepeat_dylibloader_wrapper_xlib)(Display *, int, int *);
+extern int (*XkbGetDetectableAutoRepeat_dylibloader_wrapper_xlib)(Display *, int *);
+extern int (*XkbSetAutoResetControls_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int *, unsigned int *);
+extern int (*XkbGetAutoResetControls_dylibloader_wrapper_xlib)(Display *, unsigned int *, unsigned int *);
+extern int (*XkbSetPerClientControls_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int *);
+extern int (*XkbGetPerClientControls_dylibloader_wrapper_xlib)(Display *, unsigned int *);
+extern int (*XkbCopyKeyType_dylibloader_wrapper_xlib)(XkbKeyTypePtr, XkbKeyTypePtr);
+extern int (*XkbCopyKeyTypes_dylibloader_wrapper_xlib)(XkbKeyTypePtr, XkbKeyTypePtr, int);
+extern int (*XkbResizeKeyType_dylibloader_wrapper_xlib)(XkbDescPtr, int, int, int, int);
+extern KeySym *(*XkbResizeKeySyms_dylibloader_wrapper_xlib)(XkbDescPtr, int, int);
+extern XkbAction *(*XkbResizeKeyActions_dylibloader_wrapper_xlib)(XkbDescPtr, int, int);
+extern int (*XkbChangeTypesOfKey_dylibloader_wrapper_xlib)(XkbDescPtr, int, int, unsigned int, int *, XkbMapChangesPtr);
+extern int (*XkbChangeKeycodeRange_dylibloader_wrapper_xlib)(XkbDescPtr, int, int, XkbChangesPtr);
+extern XkbComponentListPtr (*XkbListComponents_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbComponentNamesPtr, int *);
+extern void (*XkbFreeComponentList_dylibloader_wrapper_xlib)(XkbComponentListPtr);
+extern XkbDescPtr (*XkbGetKeyboard_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int);
+extern XkbDescPtr (*XkbGetKeyboardByName_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbComponentNamesPtr, unsigned int, unsigned int, int);
+extern int (*XkbKeyTypesForCoreSymbols_dylibloader_wrapper_xlib)(XkbDescPtr, int, KeySym *, unsigned int, int *, KeySym *);
+extern int (*XkbApplyCompatMapToKey_dylibloader_wrapper_xlib)(XkbDescPtr, KeyCode, XkbChangesPtr);
+extern int (*XkbUpdateMapFromCore_dylibloader_wrapper_xlib)(XkbDescPtr, KeyCode, int, int, KeySym *, XkbChangesPtr);
+extern XkbDeviceLedInfoPtr (*XkbAddDeviceLedInfo_dylibloader_wrapper_xlib)(XkbDeviceInfoPtr, unsigned int, unsigned int);
+extern int (*XkbResizeDeviceButtonActions_dylibloader_wrapper_xlib)(XkbDeviceInfoPtr, unsigned int);
+extern XkbDeviceInfoPtr (*XkbAllocDeviceInfo_dylibloader_wrapper_xlib)(unsigned int, unsigned int, unsigned int);
+extern void (*XkbFreeDeviceInfo_dylibloader_wrapper_xlib)(XkbDeviceInfoPtr, unsigned int, int);
+extern void (*XkbNoteDeviceChanges_dylibloader_wrapper_xlib)(XkbDeviceChangesPtr, XkbExtensionDeviceNotifyEvent *, unsigned int);
+extern XkbDeviceInfoPtr (*XkbGetDeviceInfo_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, unsigned int, unsigned int);
+extern int (*XkbGetDeviceInfoChanges_dylibloader_wrapper_xlib)(Display *, XkbDeviceInfoPtr, XkbDeviceChangesPtr);
+extern int (*XkbGetDeviceButtonActions_dylibloader_wrapper_xlib)(Display *, XkbDeviceInfoPtr, int, unsigned int, unsigned int);
+extern int (*XkbGetDeviceLedInfo_dylibloader_wrapper_xlib)(Display *, XkbDeviceInfoPtr, unsigned int, unsigned int, unsigned int);
+extern int (*XkbSetDeviceInfo_dylibloader_wrapper_xlib)(Display *, unsigned int, XkbDeviceInfoPtr);
+extern int (*XkbChangeDeviceInfo_dylibloader_wrapper_xlib)(Display *, XkbDeviceInfoPtr, XkbDeviceChangesPtr);
+extern int (*XkbSetDeviceLedInfo_dylibloader_wrapper_xlib)(Display *, XkbDeviceInfoPtr, unsigned int, unsigned int, unsigned int);
+extern int (*XkbSetDeviceButtonActions_dylibloader_wrapper_xlib)(Display *, XkbDeviceInfoPtr, unsigned int, unsigned int);
+extern char (*XkbToControl_dylibloader_wrapper_xlib)(char);
+extern int (*XkbSetDebuggingFlags_dylibloader_wrapper_xlib)(Display *, unsigned int, unsigned int, char *, unsigned int, unsigned int, unsigned int *, unsigned int *);
+extern int (*XkbApplyVirtualModChanges_dylibloader_wrapper_xlib)(XkbDescPtr, unsigned int, XkbChangesPtr);
+extern int (*XkbUpdateActionVirtualMods_dylibloader_wrapper_xlib)(XkbDescPtr, XkbAction *, unsigned int);
+extern void (*XkbUpdateKeyTypeVirtualMods_dylibloader_wrapper_xlib)(XkbDescPtr, XkbKeyTypePtr, unsigned int, XkbChangesPtr);
int initialize_xlib(int verbose);
#ifdef __cplusplus
}
diff --git a/platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.c b/platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.c
index 05f98d2506..bc9de62caa 100644
--- a/platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.c
+++ b/platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.c
@@ -1,12 +1,8 @@
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
-// generated by generate-wrapper.py 0.3 on 2023-01-23 15:13:54
-// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/extensions/Xrandr.h --sys-include "thirdparty/linuxbsd_headers/X11/extensions/Xrandr.h" --soname libXrandr.so.2 --init-name xrandr --output-header ./platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.c
+// generated by generate-wrapper.py 0.6 on 2024-11-09 02:52:37
+// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/extensions/Xrandr.h --sys-include thirdparty/linuxbsd_headers/X11/extensions/Xrandr.h --soname libXrandr.so.2 --init-name xrandr --output-header ./platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.c --ignore-other
//
-// NOTE: Generated from Xrandr 1.5.2.
-// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existent symbols inherited from
-// libX11 and libXrender, but absent in libXrandr.so.2, were removed.
#include <stdint.h>
#define XRRQueryExtension XRRQueryExtension_dylibloader_orig_xrandr
@@ -152,76 +148,76 @@
#undef XRRFreeMonitors
#include <dlfcn.h>
#include <stdio.h>
-int (*XRRQueryExtension_dylibloader_wrapper_xrandr)( Display*, int*, int*);
-int (*XRRQueryVersion_dylibloader_wrapper_xrandr)( Display*, int*, int*);
-XRRScreenConfiguration* (*XRRGetScreenInfo_dylibloader_wrapper_xrandr)( Display*, Window);
-void (*XRRFreeScreenConfigInfo_dylibloader_wrapper_xrandr)( XRRScreenConfiguration*);
-int (*XRRSetScreenConfig_dylibloader_wrapper_xrandr)( Display*, XRRScreenConfiguration*, Drawable, int, Rotation, Time);
-int (*XRRSetScreenConfigAndRate_dylibloader_wrapper_xrandr)( Display*, XRRScreenConfiguration*, Drawable, int, Rotation, short, Time);
-Rotation (*XRRConfigRotations_dylibloader_wrapper_xrandr)( XRRScreenConfiguration*, Rotation*);
-Time (*XRRConfigTimes_dylibloader_wrapper_xrandr)( XRRScreenConfiguration*, Time*);
-XRRScreenSize* (*XRRConfigSizes_dylibloader_wrapper_xrandr)( XRRScreenConfiguration*, int*);
-short* (*XRRConfigRates_dylibloader_wrapper_xrandr)( XRRScreenConfiguration*, int, int*);
-SizeID (*XRRConfigCurrentConfiguration_dylibloader_wrapper_xrandr)( XRRScreenConfiguration*, Rotation*);
-short (*XRRConfigCurrentRate_dylibloader_wrapper_xrandr)( XRRScreenConfiguration*);
-int (*XRRRootToScreen_dylibloader_wrapper_xrandr)( Display*, Window);
-void (*XRRSelectInput_dylibloader_wrapper_xrandr)( Display*, Window, int);
-Rotation (*XRRRotations_dylibloader_wrapper_xrandr)( Display*, int, Rotation*);
-XRRScreenSize* (*XRRSizes_dylibloader_wrapper_xrandr)( Display*, int, int*);
-short* (*XRRRates_dylibloader_wrapper_xrandr)( Display*, int, int, int*);
-Time (*XRRTimes_dylibloader_wrapper_xrandr)( Display*, int, Time*);
-int (*XRRGetScreenSizeRange_dylibloader_wrapper_xrandr)( Display*, Window, int*, int*, int*, int*);
-void (*XRRSetScreenSize_dylibloader_wrapper_xrandr)( Display*, Window, int, int, int, int);
-XRRScreenResources* (*XRRGetScreenResources_dylibloader_wrapper_xrandr)( Display*, Window);
-void (*XRRFreeScreenResources_dylibloader_wrapper_xrandr)( XRRScreenResources*);
-XRROutputInfo* (*XRRGetOutputInfo_dylibloader_wrapper_xrandr)( Display*, XRRScreenResources*, RROutput);
-void (*XRRFreeOutputInfo_dylibloader_wrapper_xrandr)( XRROutputInfo*);
-Atom* (*XRRListOutputProperties_dylibloader_wrapper_xrandr)( Display*, RROutput, int*);
-XRRPropertyInfo* (*XRRQueryOutputProperty_dylibloader_wrapper_xrandr)( Display*, RROutput, Atom);
-void (*XRRConfigureOutputProperty_dylibloader_wrapper_xrandr)( Display*, RROutput, Atom, int, int, int, long*);
-void (*XRRChangeOutputProperty_dylibloader_wrapper_xrandr)( Display*, RROutput, Atom, Atom, int, int,const unsigned char*, int);
-void (*XRRDeleteOutputProperty_dylibloader_wrapper_xrandr)( Display*, RROutput, Atom);
-int (*XRRGetOutputProperty_dylibloader_wrapper_xrandr)( Display*, RROutput, Atom, long, long, int, int, Atom, Atom*, int*, unsigned long*, unsigned long*, unsigned char**);
-XRRModeInfo* (*XRRAllocModeInfo_dylibloader_wrapper_xrandr)(const char*, int);
-RRMode (*XRRCreateMode_dylibloader_wrapper_xrandr)( Display*, Window, XRRModeInfo*);
-void (*XRRDestroyMode_dylibloader_wrapper_xrandr)( Display*, RRMode);
-void (*XRRAddOutputMode_dylibloader_wrapper_xrandr)( Display*, RROutput, RRMode);
-void (*XRRDeleteOutputMode_dylibloader_wrapper_xrandr)( Display*, RROutput, RRMode);
-void (*XRRFreeModeInfo_dylibloader_wrapper_xrandr)( XRRModeInfo*);
-XRRCrtcInfo* (*XRRGetCrtcInfo_dylibloader_wrapper_xrandr)( Display*, XRRScreenResources*, RRCrtc);
-void (*XRRFreeCrtcInfo_dylibloader_wrapper_xrandr)( XRRCrtcInfo*);
-int (*XRRSetCrtcConfig_dylibloader_wrapper_xrandr)( Display*, XRRScreenResources*, RRCrtc, Time, int, int, RRMode, Rotation, RROutput*, int);
-int (*XRRGetCrtcGammaSize_dylibloader_wrapper_xrandr)( Display*, RRCrtc);
-XRRCrtcGamma* (*XRRGetCrtcGamma_dylibloader_wrapper_xrandr)( Display*, RRCrtc);
-XRRCrtcGamma* (*XRRAllocGamma_dylibloader_wrapper_xrandr)( int);
-void (*XRRSetCrtcGamma_dylibloader_wrapper_xrandr)( Display*, RRCrtc, XRRCrtcGamma*);
-void (*XRRFreeGamma_dylibloader_wrapper_xrandr)( XRRCrtcGamma*);
-XRRScreenResources* (*XRRGetScreenResourcesCurrent_dylibloader_wrapper_xrandr)( Display*, Window);
-void (*XRRSetCrtcTransform_dylibloader_wrapper_xrandr)( Display*, RRCrtc, XTransform*,const char*, XFixed*, int);
-int (*XRRGetCrtcTransform_dylibloader_wrapper_xrandr)( Display*, RRCrtc, XRRCrtcTransformAttributes**);
-int (*XRRUpdateConfiguration_dylibloader_wrapper_xrandr)( XEvent*);
-XRRPanning* (*XRRGetPanning_dylibloader_wrapper_xrandr)( Display*, XRRScreenResources*, RRCrtc);
-void (*XRRFreePanning_dylibloader_wrapper_xrandr)( XRRPanning*);
-int (*XRRSetPanning_dylibloader_wrapper_xrandr)( Display*, XRRScreenResources*, RRCrtc, XRRPanning*);
-void (*XRRSetOutputPrimary_dylibloader_wrapper_xrandr)( Display*, Window, RROutput);
-RROutput (*XRRGetOutputPrimary_dylibloader_wrapper_xrandr)( Display*, Window);
-XRRProviderResources* (*XRRGetProviderResources_dylibloader_wrapper_xrandr)( Display*, Window);
-void (*XRRFreeProviderResources_dylibloader_wrapper_xrandr)( XRRProviderResources*);
-XRRProviderInfo* (*XRRGetProviderInfo_dylibloader_wrapper_xrandr)( Display*, XRRScreenResources*, RRProvider);
-void (*XRRFreeProviderInfo_dylibloader_wrapper_xrandr)( XRRProviderInfo*);
-int (*XRRSetProviderOutputSource_dylibloader_wrapper_xrandr)( Display*, XID, XID);
-int (*XRRSetProviderOffloadSink_dylibloader_wrapper_xrandr)( Display*, XID, XID);
-Atom* (*XRRListProviderProperties_dylibloader_wrapper_xrandr)( Display*, RRProvider, int*);
-XRRPropertyInfo* (*XRRQueryProviderProperty_dylibloader_wrapper_xrandr)( Display*, RRProvider, Atom);
-void (*XRRConfigureProviderProperty_dylibloader_wrapper_xrandr)( Display*, RRProvider, Atom, int, int, int, long*);
-void (*XRRChangeProviderProperty_dylibloader_wrapper_xrandr)( Display*, RRProvider, Atom, Atom, int, int,const unsigned char*, int);
-void (*XRRDeleteProviderProperty_dylibloader_wrapper_xrandr)( Display*, RRProvider, Atom);
-int (*XRRGetProviderProperty_dylibloader_wrapper_xrandr)( Display*, RRProvider, Atom, long, long, int, int, Atom, Atom*, int*, unsigned long*, unsigned long*, unsigned char**);
-XRRMonitorInfo* (*XRRAllocateMonitor_dylibloader_wrapper_xrandr)( Display*, int);
-XRRMonitorInfo* (*XRRGetMonitors_dylibloader_wrapper_xrandr)( Display*, Window, int, int*);
-void (*XRRSetMonitor_dylibloader_wrapper_xrandr)( Display*, Window, XRRMonitorInfo*);
-void (*XRRDeleteMonitor_dylibloader_wrapper_xrandr)( Display*, Window, Atom);
-void (*XRRFreeMonitors_dylibloader_wrapper_xrandr)( XRRMonitorInfo*);
+int (*XRRQueryExtension_dylibloader_wrapper_xrandr)(Display *, int *, int *);
+int (*XRRQueryVersion_dylibloader_wrapper_xrandr)(Display *, int *, int *);
+XRRScreenConfiguration *(*XRRGetScreenInfo_dylibloader_wrapper_xrandr)(Display *, Window);
+void (*XRRFreeScreenConfigInfo_dylibloader_wrapper_xrandr)(XRRScreenConfiguration *);
+int (*XRRSetScreenConfig_dylibloader_wrapper_xrandr)(Display *, XRRScreenConfiguration *, Drawable, int, Rotation, Time);
+int (*XRRSetScreenConfigAndRate_dylibloader_wrapper_xrandr)(Display *, XRRScreenConfiguration *, Drawable, int, Rotation, short, Time);
+Rotation (*XRRConfigRotations_dylibloader_wrapper_xrandr)(XRRScreenConfiguration *, Rotation *);
+Time (*XRRConfigTimes_dylibloader_wrapper_xrandr)(XRRScreenConfiguration *, Time *);
+XRRScreenSize *(*XRRConfigSizes_dylibloader_wrapper_xrandr)(XRRScreenConfiguration *, int *);
+short *(*XRRConfigRates_dylibloader_wrapper_xrandr)(XRRScreenConfiguration *, int, int *);
+SizeID (*XRRConfigCurrentConfiguration_dylibloader_wrapper_xrandr)(XRRScreenConfiguration *, Rotation *);
+short (*XRRConfigCurrentRate_dylibloader_wrapper_xrandr)(XRRScreenConfiguration *);
+int (*XRRRootToScreen_dylibloader_wrapper_xrandr)(Display *, Window);
+void (*XRRSelectInput_dylibloader_wrapper_xrandr)(Display *, Window, int);
+Rotation (*XRRRotations_dylibloader_wrapper_xrandr)(Display *, int, Rotation *);
+XRRScreenSize *(*XRRSizes_dylibloader_wrapper_xrandr)(Display *, int, int *);
+short *(*XRRRates_dylibloader_wrapper_xrandr)(Display *, int, int, int *);
+Time (*XRRTimes_dylibloader_wrapper_xrandr)(Display *, int, Time *);
+int (*XRRGetScreenSizeRange_dylibloader_wrapper_xrandr)(Display *, Window, int *, int *, int *, int *);
+void (*XRRSetScreenSize_dylibloader_wrapper_xrandr)(Display *, Window, int, int, int, int);
+XRRScreenResources *(*XRRGetScreenResources_dylibloader_wrapper_xrandr)(Display *, Window);
+void (*XRRFreeScreenResources_dylibloader_wrapper_xrandr)(XRRScreenResources *);
+XRROutputInfo *(*XRRGetOutputInfo_dylibloader_wrapper_xrandr)(Display *, XRRScreenResources *, RROutput);
+void (*XRRFreeOutputInfo_dylibloader_wrapper_xrandr)(XRROutputInfo *);
+Atom *(*XRRListOutputProperties_dylibloader_wrapper_xrandr)(Display *, RROutput, int *);
+XRRPropertyInfo *(*XRRQueryOutputProperty_dylibloader_wrapper_xrandr)(Display *, RROutput, Atom);
+void (*XRRConfigureOutputProperty_dylibloader_wrapper_xrandr)(Display *, RROutput, Atom, int, int, int, long *);
+void (*XRRChangeOutputProperty_dylibloader_wrapper_xrandr)(Display *, RROutput, Atom, Atom, int, int, const unsigned char *, int);
+void (*XRRDeleteOutputProperty_dylibloader_wrapper_xrandr)(Display *, RROutput, Atom);
+int (*XRRGetOutputProperty_dylibloader_wrapper_xrandr)(Display *, RROutput, Atom, long, long, int, int, Atom, Atom *, int *, unsigned long *, unsigned long *, unsigned char **);
+XRRModeInfo *(*XRRAllocModeInfo_dylibloader_wrapper_xrandr)(const char *, int);
+RRMode (*XRRCreateMode_dylibloader_wrapper_xrandr)(Display *, Window, XRRModeInfo *);
+void (*XRRDestroyMode_dylibloader_wrapper_xrandr)(Display *, RRMode);
+void (*XRRAddOutputMode_dylibloader_wrapper_xrandr)(Display *, RROutput, RRMode);
+void (*XRRDeleteOutputMode_dylibloader_wrapper_xrandr)(Display *, RROutput, RRMode);
+void (*XRRFreeModeInfo_dylibloader_wrapper_xrandr)(XRRModeInfo *);
+XRRCrtcInfo *(*XRRGetCrtcInfo_dylibloader_wrapper_xrandr)(Display *, XRRScreenResources *, RRCrtc);
+void (*XRRFreeCrtcInfo_dylibloader_wrapper_xrandr)(XRRCrtcInfo *);
+int (*XRRSetCrtcConfig_dylibloader_wrapper_xrandr)(Display *, XRRScreenResources *, RRCrtc, Time, int, int, RRMode, Rotation, RROutput *, int);
+int (*XRRGetCrtcGammaSize_dylibloader_wrapper_xrandr)(Display *, RRCrtc);
+XRRCrtcGamma *(*XRRGetCrtcGamma_dylibloader_wrapper_xrandr)(Display *, RRCrtc);
+XRRCrtcGamma *(*XRRAllocGamma_dylibloader_wrapper_xrandr)(int);
+void (*XRRSetCrtcGamma_dylibloader_wrapper_xrandr)(Display *, RRCrtc, XRRCrtcGamma *);
+void (*XRRFreeGamma_dylibloader_wrapper_xrandr)(XRRCrtcGamma *);
+XRRScreenResources *(*XRRGetScreenResourcesCurrent_dylibloader_wrapper_xrandr)(Display *, Window);
+void (*XRRSetCrtcTransform_dylibloader_wrapper_xrandr)(Display *, RRCrtc, XTransform *, const char *, XFixed *, int);
+int (*XRRGetCrtcTransform_dylibloader_wrapper_xrandr)(Display *, RRCrtc, XRRCrtcTransformAttributes **);
+int (*XRRUpdateConfiguration_dylibloader_wrapper_xrandr)(XEvent *);
+XRRPanning *(*XRRGetPanning_dylibloader_wrapper_xrandr)(Display *, XRRScreenResources *, RRCrtc);
+void (*XRRFreePanning_dylibloader_wrapper_xrandr)(XRRPanning *);
+int (*XRRSetPanning_dylibloader_wrapper_xrandr)(Display *, XRRScreenResources *, RRCrtc, XRRPanning *);
+void (*XRRSetOutputPrimary_dylibloader_wrapper_xrandr)(Display *, Window, RROutput);
+RROutput (*XRRGetOutputPrimary_dylibloader_wrapper_xrandr)(Display *, Window);
+XRRProviderResources *(*XRRGetProviderResources_dylibloader_wrapper_xrandr)(Display *, Window);
+void (*XRRFreeProviderResources_dylibloader_wrapper_xrandr)(XRRProviderResources *);
+XRRProviderInfo *(*XRRGetProviderInfo_dylibloader_wrapper_xrandr)(Display *, XRRScreenResources *, RRProvider);
+void (*XRRFreeProviderInfo_dylibloader_wrapper_xrandr)(XRRProviderInfo *);
+int (*XRRSetProviderOutputSource_dylibloader_wrapper_xrandr)(Display *, XID, XID);
+int (*XRRSetProviderOffloadSink_dylibloader_wrapper_xrandr)(Display *, XID, XID);
+Atom *(*XRRListProviderProperties_dylibloader_wrapper_xrandr)(Display *, RRProvider, int *);
+XRRPropertyInfo *(*XRRQueryProviderProperty_dylibloader_wrapper_xrandr)(Display *, RRProvider, Atom);
+void (*XRRConfigureProviderProperty_dylibloader_wrapper_xrandr)(Display *, RRProvider, Atom, int, int, int, long *);
+void (*XRRChangeProviderProperty_dylibloader_wrapper_xrandr)(Display *, RRProvider, Atom, Atom, int, int, const unsigned char *, int);
+void (*XRRDeleteProviderProperty_dylibloader_wrapper_xrandr)(Display *, RRProvider, Atom);
+int (*XRRGetProviderProperty_dylibloader_wrapper_xrandr)(Display *, RRProvider, Atom, long, long, int, int, Atom, Atom *, int *, unsigned long *, unsigned long *, unsigned char **);
+XRRMonitorInfo *(*XRRAllocateMonitor_dylibloader_wrapper_xrandr)(Display *, int);
+XRRMonitorInfo *(*XRRGetMonitors_dylibloader_wrapper_xrandr)(Display *, Window, int, int *);
+void (*XRRSetMonitor_dylibloader_wrapper_xrandr)(Display *, Window, XRRMonitorInfo *);
+void (*XRRDeleteMonitor_dylibloader_wrapper_xrandr)(Display *, Window, Atom);
+void (*XRRFreeMonitors_dylibloader_wrapper_xrandr)(XRRMonitorInfo *);
int initialize_xrandr(int verbose) {
void *handle;
char *error;
diff --git a/platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.h b/platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.h
index db5d44203d..c055705f69 100644
--- a/platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.h
+++ b/platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.h
@@ -2,13 +2,9 @@
#define DYLIBLOAD_WRAPPER_XRANDR
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
-// generated by generate-wrapper.py 0.3 on 2023-01-23 15:13:54
-// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/extensions/Xrandr.h --sys-include "thirdparty/linuxbsd_headers/X11/extensions/Xrandr.h" --soname libXrandr.so.2 --init-name xrandr --output-header ./platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.c
+// generated by generate-wrapper.py 0.6 on 2024-11-09 02:52:37
+// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/extensions/Xrandr.h --sys-include thirdparty/linuxbsd_headers/X11/extensions/Xrandr.h --soname libXrandr.so.2 --init-name xrandr --output-header ./platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xrandr-so_wrap.c --ignore-other
//
-// NOTE: Generated from Xrandr 1.5.2.
-// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existent symbols inherited from
-// libX11 and libXrender, but absent in libXrandr.so.2, were removed.
#include <stdint.h>
#define XRRQueryExtension XRRQueryExtension_dylibloader_orig_xrandr
@@ -225,76 +221,76 @@ extern "C" {
#define XRRSetMonitor XRRSetMonitor_dylibloader_wrapper_xrandr
#define XRRDeleteMonitor XRRDeleteMonitor_dylibloader_wrapper_xrandr
#define XRRFreeMonitors XRRFreeMonitors_dylibloader_wrapper_xrandr
-extern int (*XRRQueryExtension_dylibloader_wrapper_xrandr)( Display*, int*, int*);
-extern int (*XRRQueryVersion_dylibloader_wrapper_xrandr)( Display*, int*, int*);
-extern XRRScreenConfiguration* (*XRRGetScreenInfo_dylibloader_wrapper_xrandr)( Display*, Window);
-extern void (*XRRFreeScreenConfigInfo_dylibloader_wrapper_xrandr)( XRRScreenConfiguration*);
-extern int (*XRRSetScreenConfig_dylibloader_wrapper_xrandr)( Display*, XRRScreenConfiguration*, Drawable, int, Rotation, Time);
-extern int (*XRRSetScreenConfigAndRate_dylibloader_wrapper_xrandr)( Display*, XRRScreenConfiguration*, Drawable, int, Rotation, short, Time);
-extern Rotation (*XRRConfigRotations_dylibloader_wrapper_xrandr)( XRRScreenConfiguration*, Rotation*);
-extern Time (*XRRConfigTimes_dylibloader_wrapper_xrandr)( XRRScreenConfiguration*, Time*);
-extern XRRScreenSize* (*XRRConfigSizes_dylibloader_wrapper_xrandr)( XRRScreenConfiguration*, int*);
-extern short* (*XRRConfigRates_dylibloader_wrapper_xrandr)( XRRScreenConfiguration*, int, int*);
-extern SizeID (*XRRConfigCurrentConfiguration_dylibloader_wrapper_xrandr)( XRRScreenConfiguration*, Rotation*);
-extern short (*XRRConfigCurrentRate_dylibloader_wrapper_xrandr)( XRRScreenConfiguration*);
-extern int (*XRRRootToScreen_dylibloader_wrapper_xrandr)( Display*, Window);
-extern void (*XRRSelectInput_dylibloader_wrapper_xrandr)( Display*, Window, int);
-extern Rotation (*XRRRotations_dylibloader_wrapper_xrandr)( Display*, int, Rotation*);
-extern XRRScreenSize* (*XRRSizes_dylibloader_wrapper_xrandr)( Display*, int, int*);
-extern short* (*XRRRates_dylibloader_wrapper_xrandr)( Display*, int, int, int*);
-extern Time (*XRRTimes_dylibloader_wrapper_xrandr)( Display*, int, Time*);
-extern int (*XRRGetScreenSizeRange_dylibloader_wrapper_xrandr)( Display*, Window, int*, int*, int*, int*);
-extern void (*XRRSetScreenSize_dylibloader_wrapper_xrandr)( Display*, Window, int, int, int, int);
-extern XRRScreenResources* (*XRRGetScreenResources_dylibloader_wrapper_xrandr)( Display*, Window);
-extern void (*XRRFreeScreenResources_dylibloader_wrapper_xrandr)( XRRScreenResources*);
-extern XRROutputInfo* (*XRRGetOutputInfo_dylibloader_wrapper_xrandr)( Display*, XRRScreenResources*, RROutput);
-extern void (*XRRFreeOutputInfo_dylibloader_wrapper_xrandr)( XRROutputInfo*);
-extern Atom* (*XRRListOutputProperties_dylibloader_wrapper_xrandr)( Display*, RROutput, int*);
-extern XRRPropertyInfo* (*XRRQueryOutputProperty_dylibloader_wrapper_xrandr)( Display*, RROutput, Atom);
-extern void (*XRRConfigureOutputProperty_dylibloader_wrapper_xrandr)( Display*, RROutput, Atom, int, int, int, long*);
-extern void (*XRRChangeOutputProperty_dylibloader_wrapper_xrandr)( Display*, RROutput, Atom, Atom, int, int,const unsigned char*, int);
-extern void (*XRRDeleteOutputProperty_dylibloader_wrapper_xrandr)( Display*, RROutput, Atom);
-extern int (*XRRGetOutputProperty_dylibloader_wrapper_xrandr)( Display*, RROutput, Atom, long, long, int, int, Atom, Atom*, int*, unsigned long*, unsigned long*, unsigned char**);
-extern XRRModeInfo* (*XRRAllocModeInfo_dylibloader_wrapper_xrandr)(const char*, int);
-extern RRMode (*XRRCreateMode_dylibloader_wrapper_xrandr)( Display*, Window, XRRModeInfo*);
-extern void (*XRRDestroyMode_dylibloader_wrapper_xrandr)( Display*, RRMode);
-extern void (*XRRAddOutputMode_dylibloader_wrapper_xrandr)( Display*, RROutput, RRMode);
-extern void (*XRRDeleteOutputMode_dylibloader_wrapper_xrandr)( Display*, RROutput, RRMode);
-extern void (*XRRFreeModeInfo_dylibloader_wrapper_xrandr)( XRRModeInfo*);
-extern XRRCrtcInfo* (*XRRGetCrtcInfo_dylibloader_wrapper_xrandr)( Display*, XRRScreenResources*, RRCrtc);
-extern void (*XRRFreeCrtcInfo_dylibloader_wrapper_xrandr)( XRRCrtcInfo*);
-extern int (*XRRSetCrtcConfig_dylibloader_wrapper_xrandr)( Display*, XRRScreenResources*, RRCrtc, Time, int, int, RRMode, Rotation, RROutput*, int);
-extern int (*XRRGetCrtcGammaSize_dylibloader_wrapper_xrandr)( Display*, RRCrtc);
-extern XRRCrtcGamma* (*XRRGetCrtcGamma_dylibloader_wrapper_xrandr)( Display*, RRCrtc);
-extern XRRCrtcGamma* (*XRRAllocGamma_dylibloader_wrapper_xrandr)( int);
-extern void (*XRRSetCrtcGamma_dylibloader_wrapper_xrandr)( Display*, RRCrtc, XRRCrtcGamma*);
-extern void (*XRRFreeGamma_dylibloader_wrapper_xrandr)( XRRCrtcGamma*);
-extern XRRScreenResources* (*XRRGetScreenResourcesCurrent_dylibloader_wrapper_xrandr)( Display*, Window);
-extern void (*XRRSetCrtcTransform_dylibloader_wrapper_xrandr)( Display*, RRCrtc, XTransform*,const char*, XFixed*, int);
-extern int (*XRRGetCrtcTransform_dylibloader_wrapper_xrandr)( Display*, RRCrtc, XRRCrtcTransformAttributes**);
-extern int (*XRRUpdateConfiguration_dylibloader_wrapper_xrandr)( XEvent*);
-extern XRRPanning* (*XRRGetPanning_dylibloader_wrapper_xrandr)( Display*, XRRScreenResources*, RRCrtc);
-extern void (*XRRFreePanning_dylibloader_wrapper_xrandr)( XRRPanning*);
-extern int (*XRRSetPanning_dylibloader_wrapper_xrandr)( Display*, XRRScreenResources*, RRCrtc, XRRPanning*);
-extern void (*XRRSetOutputPrimary_dylibloader_wrapper_xrandr)( Display*, Window, RROutput);
-extern RROutput (*XRRGetOutputPrimary_dylibloader_wrapper_xrandr)( Display*, Window);
-extern XRRProviderResources* (*XRRGetProviderResources_dylibloader_wrapper_xrandr)( Display*, Window);
-extern void (*XRRFreeProviderResources_dylibloader_wrapper_xrandr)( XRRProviderResources*);
-extern XRRProviderInfo* (*XRRGetProviderInfo_dylibloader_wrapper_xrandr)( Display*, XRRScreenResources*, RRProvider);
-extern void (*XRRFreeProviderInfo_dylibloader_wrapper_xrandr)( XRRProviderInfo*);
-extern int (*XRRSetProviderOutputSource_dylibloader_wrapper_xrandr)( Display*, XID, XID);
-extern int (*XRRSetProviderOffloadSink_dylibloader_wrapper_xrandr)( Display*, XID, XID);
-extern Atom* (*XRRListProviderProperties_dylibloader_wrapper_xrandr)( Display*, RRProvider, int*);
-extern XRRPropertyInfo* (*XRRQueryProviderProperty_dylibloader_wrapper_xrandr)( Display*, RRProvider, Atom);
-extern void (*XRRConfigureProviderProperty_dylibloader_wrapper_xrandr)( Display*, RRProvider, Atom, int, int, int, long*);
-extern void (*XRRChangeProviderProperty_dylibloader_wrapper_xrandr)( Display*, RRProvider, Atom, Atom, int, int,const unsigned char*, int);
-extern void (*XRRDeleteProviderProperty_dylibloader_wrapper_xrandr)( Display*, RRProvider, Atom);
-extern int (*XRRGetProviderProperty_dylibloader_wrapper_xrandr)( Display*, RRProvider, Atom, long, long, int, int, Atom, Atom*, int*, unsigned long*, unsigned long*, unsigned char**);
-extern XRRMonitorInfo* (*XRRAllocateMonitor_dylibloader_wrapper_xrandr)( Display*, int);
-extern XRRMonitorInfo* (*XRRGetMonitors_dylibloader_wrapper_xrandr)( Display*, Window, int, int*);
-extern void (*XRRSetMonitor_dylibloader_wrapper_xrandr)( Display*, Window, XRRMonitorInfo*);
-extern void (*XRRDeleteMonitor_dylibloader_wrapper_xrandr)( Display*, Window, Atom);
-extern void (*XRRFreeMonitors_dylibloader_wrapper_xrandr)( XRRMonitorInfo*);
+extern int (*XRRQueryExtension_dylibloader_wrapper_xrandr)(Display *, int *, int *);
+extern int (*XRRQueryVersion_dylibloader_wrapper_xrandr)(Display *, int *, int *);
+extern XRRScreenConfiguration *(*XRRGetScreenInfo_dylibloader_wrapper_xrandr)(Display *, Window);
+extern void (*XRRFreeScreenConfigInfo_dylibloader_wrapper_xrandr)(XRRScreenConfiguration *);
+extern int (*XRRSetScreenConfig_dylibloader_wrapper_xrandr)(Display *, XRRScreenConfiguration *, Drawable, int, Rotation, Time);
+extern int (*XRRSetScreenConfigAndRate_dylibloader_wrapper_xrandr)(Display *, XRRScreenConfiguration *, Drawable, int, Rotation, short, Time);
+extern Rotation (*XRRConfigRotations_dylibloader_wrapper_xrandr)(XRRScreenConfiguration *, Rotation *);
+extern Time (*XRRConfigTimes_dylibloader_wrapper_xrandr)(XRRScreenConfiguration *, Time *);
+extern XRRScreenSize *(*XRRConfigSizes_dylibloader_wrapper_xrandr)(XRRScreenConfiguration *, int *);
+extern short *(*XRRConfigRates_dylibloader_wrapper_xrandr)(XRRScreenConfiguration *, int, int *);
+extern SizeID (*XRRConfigCurrentConfiguration_dylibloader_wrapper_xrandr)(XRRScreenConfiguration *, Rotation *);
+extern short (*XRRConfigCurrentRate_dylibloader_wrapper_xrandr)(XRRScreenConfiguration *);
+extern int (*XRRRootToScreen_dylibloader_wrapper_xrandr)(Display *, Window);
+extern void (*XRRSelectInput_dylibloader_wrapper_xrandr)(Display *, Window, int);
+extern Rotation (*XRRRotations_dylibloader_wrapper_xrandr)(Display *, int, Rotation *);
+extern XRRScreenSize *(*XRRSizes_dylibloader_wrapper_xrandr)(Display *, int, int *);
+extern short *(*XRRRates_dylibloader_wrapper_xrandr)(Display *, int, int, int *);
+extern Time (*XRRTimes_dylibloader_wrapper_xrandr)(Display *, int, Time *);
+extern int (*XRRGetScreenSizeRange_dylibloader_wrapper_xrandr)(Display *, Window, int *, int *, int *, int *);
+extern void (*XRRSetScreenSize_dylibloader_wrapper_xrandr)(Display *, Window, int, int, int, int);
+extern XRRScreenResources *(*XRRGetScreenResources_dylibloader_wrapper_xrandr)(Display *, Window);
+extern void (*XRRFreeScreenResources_dylibloader_wrapper_xrandr)(XRRScreenResources *);
+extern XRROutputInfo *(*XRRGetOutputInfo_dylibloader_wrapper_xrandr)(Display *, XRRScreenResources *, RROutput);
+extern void (*XRRFreeOutputInfo_dylibloader_wrapper_xrandr)(XRROutputInfo *);
+extern Atom *(*XRRListOutputProperties_dylibloader_wrapper_xrandr)(Display *, RROutput, int *);
+extern XRRPropertyInfo *(*XRRQueryOutputProperty_dylibloader_wrapper_xrandr)(Display *, RROutput, Atom);
+extern void (*XRRConfigureOutputProperty_dylibloader_wrapper_xrandr)(Display *, RROutput, Atom, int, int, int, long *);
+extern void (*XRRChangeOutputProperty_dylibloader_wrapper_xrandr)(Display *, RROutput, Atom, Atom, int, int, const unsigned char *, int);
+extern void (*XRRDeleteOutputProperty_dylibloader_wrapper_xrandr)(Display *, RROutput, Atom);
+extern int (*XRRGetOutputProperty_dylibloader_wrapper_xrandr)(Display *, RROutput, Atom, long, long, int, int, Atom, Atom *, int *, unsigned long *, unsigned long *, unsigned char **);
+extern XRRModeInfo *(*XRRAllocModeInfo_dylibloader_wrapper_xrandr)(const char *, int);
+extern RRMode (*XRRCreateMode_dylibloader_wrapper_xrandr)(Display *, Window, XRRModeInfo *);
+extern void (*XRRDestroyMode_dylibloader_wrapper_xrandr)(Display *, RRMode);
+extern void (*XRRAddOutputMode_dylibloader_wrapper_xrandr)(Display *, RROutput, RRMode);
+extern void (*XRRDeleteOutputMode_dylibloader_wrapper_xrandr)(Display *, RROutput, RRMode);
+extern void (*XRRFreeModeInfo_dylibloader_wrapper_xrandr)(XRRModeInfo *);
+extern XRRCrtcInfo *(*XRRGetCrtcInfo_dylibloader_wrapper_xrandr)(Display *, XRRScreenResources *, RRCrtc);
+extern void (*XRRFreeCrtcInfo_dylibloader_wrapper_xrandr)(XRRCrtcInfo *);
+extern int (*XRRSetCrtcConfig_dylibloader_wrapper_xrandr)(Display *, XRRScreenResources *, RRCrtc, Time, int, int, RRMode, Rotation, RROutput *, int);
+extern int (*XRRGetCrtcGammaSize_dylibloader_wrapper_xrandr)(Display *, RRCrtc);
+extern XRRCrtcGamma *(*XRRGetCrtcGamma_dylibloader_wrapper_xrandr)(Display *, RRCrtc);
+extern XRRCrtcGamma *(*XRRAllocGamma_dylibloader_wrapper_xrandr)(int);
+extern void (*XRRSetCrtcGamma_dylibloader_wrapper_xrandr)(Display *, RRCrtc, XRRCrtcGamma *);
+extern void (*XRRFreeGamma_dylibloader_wrapper_xrandr)(XRRCrtcGamma *);
+extern XRRScreenResources *(*XRRGetScreenResourcesCurrent_dylibloader_wrapper_xrandr)(Display *, Window);
+extern void (*XRRSetCrtcTransform_dylibloader_wrapper_xrandr)(Display *, RRCrtc, XTransform *, const char *, XFixed *, int);
+extern int (*XRRGetCrtcTransform_dylibloader_wrapper_xrandr)(Display *, RRCrtc, XRRCrtcTransformAttributes **);
+extern int (*XRRUpdateConfiguration_dylibloader_wrapper_xrandr)(XEvent *);
+extern XRRPanning *(*XRRGetPanning_dylibloader_wrapper_xrandr)(Display *, XRRScreenResources *, RRCrtc);
+extern void (*XRRFreePanning_dylibloader_wrapper_xrandr)(XRRPanning *);
+extern int (*XRRSetPanning_dylibloader_wrapper_xrandr)(Display *, XRRScreenResources *, RRCrtc, XRRPanning *);
+extern void (*XRRSetOutputPrimary_dylibloader_wrapper_xrandr)(Display *, Window, RROutput);
+extern RROutput (*XRRGetOutputPrimary_dylibloader_wrapper_xrandr)(Display *, Window);
+extern XRRProviderResources *(*XRRGetProviderResources_dylibloader_wrapper_xrandr)(Display *, Window);
+extern void (*XRRFreeProviderResources_dylibloader_wrapper_xrandr)(XRRProviderResources *);
+extern XRRProviderInfo *(*XRRGetProviderInfo_dylibloader_wrapper_xrandr)(Display *, XRRScreenResources *, RRProvider);
+extern void (*XRRFreeProviderInfo_dylibloader_wrapper_xrandr)(XRRProviderInfo *);
+extern int (*XRRSetProviderOutputSource_dylibloader_wrapper_xrandr)(Display *, XID, XID);
+extern int (*XRRSetProviderOffloadSink_dylibloader_wrapper_xrandr)(Display *, XID, XID);
+extern Atom *(*XRRListProviderProperties_dylibloader_wrapper_xrandr)(Display *, RRProvider, int *);
+extern XRRPropertyInfo *(*XRRQueryProviderProperty_dylibloader_wrapper_xrandr)(Display *, RRProvider, Atom);
+extern void (*XRRConfigureProviderProperty_dylibloader_wrapper_xrandr)(Display *, RRProvider, Atom, int, int, int, long *);
+extern void (*XRRChangeProviderProperty_dylibloader_wrapper_xrandr)(Display *, RRProvider, Atom, Atom, int, int, const unsigned char *, int);
+extern void (*XRRDeleteProviderProperty_dylibloader_wrapper_xrandr)(Display *, RRProvider, Atom);
+extern int (*XRRGetProviderProperty_dylibloader_wrapper_xrandr)(Display *, RRProvider, Atom, long, long, int, int, Atom, Atom *, int *, unsigned long *, unsigned long *, unsigned char **);
+extern XRRMonitorInfo *(*XRRAllocateMonitor_dylibloader_wrapper_xrandr)(Display *, int);
+extern XRRMonitorInfo *(*XRRGetMonitors_dylibloader_wrapper_xrandr)(Display *, Window, int, int *);
+extern void (*XRRSetMonitor_dylibloader_wrapper_xrandr)(Display *, Window, XRRMonitorInfo *);
+extern void (*XRRDeleteMonitor_dylibloader_wrapper_xrandr)(Display *, Window, Atom);
+extern void (*XRRFreeMonitors_dylibloader_wrapper_xrandr)(XRRMonitorInfo *);
int initialize_xrandr(int verbose);
#ifdef __cplusplus
}
diff --git a/platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.c b/platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.c
index 7421f94601..e1cd987eca 100644
--- a/platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.c
+++ b/platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.c
@@ -1,12 +1,8 @@
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
-// generated by generate-wrapper.py 0.3 on 2023-01-23 15:14:14
-// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/extensions/Xrender.h --sys-include "thirdparty/linuxbsd_headers/X11/extensions/Xrender.h" --soname libXrender.so.1 --init-name xrender --output-header ./platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.c~
+// generated by generate-wrapper.py 0.6 on 2024-11-09 02:52:37
+// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/extensions/Xrender.h --sys-include thirdparty/linuxbsd_headers/X11/extensions/Xrender.h --soname libXrender.so.1 --init-name xrender --output-header ./platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.c --ignore-other
//
-// NOTE: Generated from Xrender 0.9.10.
-// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existent symbols inherited from
-// libX11, but absent in libXrender.so.1, were removed.
#include <stdint.h>
#define XRenderQueryExtension XRenderQueryExtension_dylibloader_orig_xrender
@@ -100,50 +96,50 @@
#undef XRenderCreateConicalGradient
#include <dlfcn.h>
#include <stdio.h>
-int (*XRenderQueryExtension_dylibloader_wrapper_xrender)( Display*, int*, int*);
-int (*XRenderQueryVersion_dylibloader_wrapper_xrender)( Display*, int*, int*);
-int (*XRenderQueryFormats_dylibloader_wrapper_xrender)( Display*);
-int (*XRenderQuerySubpixelOrder_dylibloader_wrapper_xrender)( Display*, int);
-int (*XRenderSetSubpixelOrder_dylibloader_wrapper_xrender)( Display*, int, int);
-XRenderPictFormat* (*XRenderFindVisualFormat_dylibloader_wrapper_xrender)( Display*,const Visual*);
-XRenderPictFormat* (*XRenderFindFormat_dylibloader_wrapper_xrender)( Display*, unsigned long,const XRenderPictFormat*, int);
-XRenderPictFormat* (*XRenderFindStandardFormat_dylibloader_wrapper_xrender)( Display*, int);
-XIndexValue* (*XRenderQueryPictIndexValues_dylibloader_wrapper_xrender)( Display*,const XRenderPictFormat*, int*);
-Picture (*XRenderCreatePicture_dylibloader_wrapper_xrender)( Display*, Drawable,const XRenderPictFormat*, unsigned long,const XRenderPictureAttributes*);
-void (*XRenderChangePicture_dylibloader_wrapper_xrender)( Display*, Picture, unsigned long,const XRenderPictureAttributes*);
-void (*XRenderSetPictureClipRectangles_dylibloader_wrapper_xrender)( Display*, Picture, int, int,const XRectangle*, int);
-void (*XRenderSetPictureClipRegion_dylibloader_wrapper_xrender)( Display*, Picture, Region);
-void (*XRenderSetPictureTransform_dylibloader_wrapper_xrender)( Display*, Picture, XTransform*);
-void (*XRenderFreePicture_dylibloader_wrapper_xrender)( Display*, Picture);
-void (*XRenderComposite_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture, Picture, int, int, int, int, int, int, unsigned int, unsigned int);
-GlyphSet (*XRenderCreateGlyphSet_dylibloader_wrapper_xrender)( Display*,const XRenderPictFormat*);
-GlyphSet (*XRenderReferenceGlyphSet_dylibloader_wrapper_xrender)( Display*, GlyphSet);
-void (*XRenderFreeGlyphSet_dylibloader_wrapper_xrender)( Display*, GlyphSet);
-void (*XRenderAddGlyphs_dylibloader_wrapper_xrender)( Display*, GlyphSet,const Glyph*,const XGlyphInfo*, int,const char*, int);
-void (*XRenderFreeGlyphs_dylibloader_wrapper_xrender)( Display*, GlyphSet,const Glyph*, int);
-void (*XRenderCompositeString8_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, GlyphSet, int, int, int, int,const char*, int);
-void (*XRenderCompositeString16_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, GlyphSet, int, int, int, int,const unsigned short*, int);
-void (*XRenderCompositeString32_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, GlyphSet, int, int, int, int,const unsigned int*, int);
-void (*XRenderCompositeText8_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, int, int, int, int,const XGlyphElt8*, int);
-void (*XRenderCompositeText16_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, int, int, int, int,const XGlyphElt16*, int);
-void (*XRenderCompositeText32_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, int, int, int, int,const XGlyphElt32*, int);
-void (*XRenderFillRectangle_dylibloader_wrapper_xrender)( Display*, int, Picture,const XRenderColor*, int, int, unsigned int, unsigned int);
-void (*XRenderFillRectangles_dylibloader_wrapper_xrender)( Display*, int, Picture,const XRenderColor*,const XRectangle*, int);
-void (*XRenderCompositeTrapezoids_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, int, int,const XTrapezoid*, int);
-void (*XRenderCompositeTriangles_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, int, int,const XTriangle*, int);
-void (*XRenderCompositeTriStrip_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, int, int,const XPointFixed*, int);
-void (*XRenderCompositeTriFan_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, int, int,const XPointFixed*, int);
-void (*XRenderCompositeDoublePoly_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, int, int, int, int,const XPointDouble*, int, int);
-int (*XRenderParseColor_dylibloader_wrapper_xrender)( Display*, char*, XRenderColor*);
-Cursor (*XRenderCreateCursor_dylibloader_wrapper_xrender)( Display*, Picture, unsigned int, unsigned int);
-XFilters* (*XRenderQueryFilters_dylibloader_wrapper_xrender)( Display*, Drawable);
-void (*XRenderSetPictureFilter_dylibloader_wrapper_xrender)( Display*, Picture,const char*, XFixed*, int);
-Cursor (*XRenderCreateAnimCursor_dylibloader_wrapper_xrender)( Display*, int, XAnimCursor*);
-void (*XRenderAddTraps_dylibloader_wrapper_xrender)( Display*, Picture, int, int,const XTrap*, int);
-Picture (*XRenderCreateSolidFill_dylibloader_wrapper_xrender)( Display*,const XRenderColor*);
-Picture (*XRenderCreateLinearGradient_dylibloader_wrapper_xrender)( Display*,const XLinearGradient*,const XFixed*,const XRenderColor*, int);
-Picture (*XRenderCreateRadialGradient_dylibloader_wrapper_xrender)( Display*,const XRadialGradient*,const XFixed*,const XRenderColor*, int);
-Picture (*XRenderCreateConicalGradient_dylibloader_wrapper_xrender)( Display*,const XConicalGradient*,const XFixed*,const XRenderColor*, int);
+int (*XRenderQueryExtension_dylibloader_wrapper_xrender)(Display *, int *, int *);
+int (*XRenderQueryVersion_dylibloader_wrapper_xrender)(Display *, int *, int *);
+int (*XRenderQueryFormats_dylibloader_wrapper_xrender)(Display *);
+int (*XRenderQuerySubpixelOrder_dylibloader_wrapper_xrender)(Display *, int);
+int (*XRenderSetSubpixelOrder_dylibloader_wrapper_xrender)(Display *, int, int);
+XRenderPictFormat *(*XRenderFindVisualFormat_dylibloader_wrapper_xrender)(Display *, const Visual *);
+XRenderPictFormat *(*XRenderFindFormat_dylibloader_wrapper_xrender)(Display *, unsigned long, const XRenderPictFormat *, int);
+XRenderPictFormat *(*XRenderFindStandardFormat_dylibloader_wrapper_xrender)(Display *, int);
+XIndexValue *(*XRenderQueryPictIndexValues_dylibloader_wrapper_xrender)(Display *, const XRenderPictFormat *, int *);
+Picture (*XRenderCreatePicture_dylibloader_wrapper_xrender)(Display *, Drawable, const XRenderPictFormat *, unsigned long, const XRenderPictureAttributes *);
+void (*XRenderChangePicture_dylibloader_wrapper_xrender)(Display *, Picture, unsigned long, const XRenderPictureAttributes *);
+void (*XRenderSetPictureClipRectangles_dylibloader_wrapper_xrender)(Display *, Picture, int, int, const XRectangle *, int);
+void (*XRenderSetPictureClipRegion_dylibloader_wrapper_xrender)(Display *, Picture, Region);
+void (*XRenderSetPictureTransform_dylibloader_wrapper_xrender)(Display *, Picture, XTransform *);
+void (*XRenderFreePicture_dylibloader_wrapper_xrender)(Display *, Picture);
+void (*XRenderComposite_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, Picture, int, int, int, int, int, int, unsigned int, unsigned int);
+GlyphSet (*XRenderCreateGlyphSet_dylibloader_wrapper_xrender)(Display *, const XRenderPictFormat *);
+GlyphSet (*XRenderReferenceGlyphSet_dylibloader_wrapper_xrender)(Display *, GlyphSet);
+void (*XRenderFreeGlyphSet_dylibloader_wrapper_xrender)(Display *, GlyphSet);
+void (*XRenderAddGlyphs_dylibloader_wrapper_xrender)(Display *, GlyphSet, const Glyph *, const XGlyphInfo *, int, const char *, int);
+void (*XRenderFreeGlyphs_dylibloader_wrapper_xrender)(Display *, GlyphSet, const Glyph *, int);
+void (*XRenderCompositeString8_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, GlyphSet, int, int, int, int, const char *, int);
+void (*XRenderCompositeString16_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, GlyphSet, int, int, int, int, const unsigned short *, int);
+void (*XRenderCompositeString32_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, GlyphSet, int, int, int, int, const unsigned int *, int);
+void (*XRenderCompositeText8_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, int, int, int, int, const XGlyphElt8 *, int);
+void (*XRenderCompositeText16_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, int, int, int, int, const XGlyphElt16 *, int);
+void (*XRenderCompositeText32_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, int, int, int, int, const XGlyphElt32 *, int);
+void (*XRenderFillRectangle_dylibloader_wrapper_xrender)(Display *, int, Picture, const XRenderColor *, int, int, unsigned int, unsigned int);
+void (*XRenderFillRectangles_dylibloader_wrapper_xrender)(Display *, int, Picture, const XRenderColor *, const XRectangle *, int);
+void (*XRenderCompositeTrapezoids_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, int, int, const XTrapezoid *, int);
+void (*XRenderCompositeTriangles_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, int, int, const XTriangle *, int);
+void (*XRenderCompositeTriStrip_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, int, int, const XPointFixed *, int);
+void (*XRenderCompositeTriFan_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, int, int, const XPointFixed *, int);
+void (*XRenderCompositeDoublePoly_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, int, int, int, int, const XPointDouble *, int, int);
+int (*XRenderParseColor_dylibloader_wrapper_xrender)(Display *, char *, XRenderColor *);
+Cursor (*XRenderCreateCursor_dylibloader_wrapper_xrender)(Display *, Picture, unsigned int, unsigned int);
+XFilters *(*XRenderQueryFilters_dylibloader_wrapper_xrender)(Display *, Drawable);
+void (*XRenderSetPictureFilter_dylibloader_wrapper_xrender)(Display *, Picture, const char *, XFixed *, int);
+Cursor (*XRenderCreateAnimCursor_dylibloader_wrapper_xrender)(Display *, int, XAnimCursor *);
+void (*XRenderAddTraps_dylibloader_wrapper_xrender)(Display *, Picture, int, int, const XTrap *, int);
+Picture (*XRenderCreateSolidFill_dylibloader_wrapper_xrender)(Display *, const XRenderColor *);
+Picture (*XRenderCreateLinearGradient_dylibloader_wrapper_xrender)(Display *, const XLinearGradient *, const XFixed *, const XRenderColor *, int);
+Picture (*XRenderCreateRadialGradient_dylibloader_wrapper_xrender)(Display *, const XRadialGradient *, const XFixed *, const XRenderColor *, int);
+Picture (*XRenderCreateConicalGradient_dylibloader_wrapper_xrender)(Display *, const XConicalGradient *, const XFixed *, const XRenderColor *, int);
int initialize_xrender(int verbose) {
void *handle;
char *error;
diff --git a/platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.h b/platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.h
index 5d3f695959..3d0e8901ea 100644
--- a/platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.h
+++ b/platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.h
@@ -2,13 +2,9 @@
#define DYLIBLOAD_WRAPPER_XRENDER
// This file is generated. Do not edit!
// see https://github.com/hpvb/dynload-wrapper for details
-// generated by generate-wrapper.py 0.3 on 2023-01-23 15:14:14
-// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/extensions/Xrender.h --sys-include "thirdparty/linuxbsd_headers/X11/extensions/Xrender.h" --soname libXrender.so.1 --init-name xrender --output-header ./platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.c~
+// generated by generate-wrapper.py 0.6 on 2024-11-09 02:52:37
+// flags: generate-wrapper.py --include ./thirdparty/linuxbsd_headers/X11/extensions/Xrender.h --sys-include thirdparty/linuxbsd_headers/X11/extensions/Xrender.h --soname libXrender.so.1 --init-name xrender --output-header ./platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.h --output-implementation ./platform/linuxbsd/x11/dynwrappers/xrender-so_wrap.c --ignore-other
//
-// NOTE: Generated from Xrender 0.9.10.
-// This has been handpatched to workaround some issues with the generator that
-// will be eventually fixed. In this case, non-existent symbols inherited from
-// libX11, but absent in libXrender.so.1, were removed.
#include <stdint.h>
#define XRenderQueryExtension XRenderQueryExtension_dylibloader_orig_xrender
@@ -147,50 +143,50 @@ extern "C" {
#define XRenderCreateLinearGradient XRenderCreateLinearGradient_dylibloader_wrapper_xrender
#define XRenderCreateRadialGradient XRenderCreateRadialGradient_dylibloader_wrapper_xrender
#define XRenderCreateConicalGradient XRenderCreateConicalGradient_dylibloader_wrapper_xrender
-extern int (*XRenderQueryExtension_dylibloader_wrapper_xrender)( Display*, int*, int*);
-extern int (*XRenderQueryVersion_dylibloader_wrapper_xrender)( Display*, int*, int*);
-extern int (*XRenderQueryFormats_dylibloader_wrapper_xrender)( Display*);
-extern int (*XRenderQuerySubpixelOrder_dylibloader_wrapper_xrender)( Display*, int);
-extern int (*XRenderSetSubpixelOrder_dylibloader_wrapper_xrender)( Display*, int, int);
-extern XRenderPictFormat* (*XRenderFindVisualFormat_dylibloader_wrapper_xrender)( Display*,const Visual*);
-extern XRenderPictFormat* (*XRenderFindFormat_dylibloader_wrapper_xrender)( Display*, unsigned long,const XRenderPictFormat*, int);
-extern XRenderPictFormat* (*XRenderFindStandardFormat_dylibloader_wrapper_xrender)( Display*, int);
-extern XIndexValue* (*XRenderQueryPictIndexValues_dylibloader_wrapper_xrender)( Display*,const XRenderPictFormat*, int*);
-extern Picture (*XRenderCreatePicture_dylibloader_wrapper_xrender)( Display*, Drawable,const XRenderPictFormat*, unsigned long,const XRenderPictureAttributes*);
-extern void (*XRenderChangePicture_dylibloader_wrapper_xrender)( Display*, Picture, unsigned long,const XRenderPictureAttributes*);
-extern void (*XRenderSetPictureClipRectangles_dylibloader_wrapper_xrender)( Display*, Picture, int, int,const XRectangle*, int);
-extern void (*XRenderSetPictureClipRegion_dylibloader_wrapper_xrender)( Display*, Picture, Region);
-extern void (*XRenderSetPictureTransform_dylibloader_wrapper_xrender)( Display*, Picture, XTransform*);
-extern void (*XRenderFreePicture_dylibloader_wrapper_xrender)( Display*, Picture);
-extern void (*XRenderComposite_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture, Picture, int, int, int, int, int, int, unsigned int, unsigned int);
-extern GlyphSet (*XRenderCreateGlyphSet_dylibloader_wrapper_xrender)( Display*,const XRenderPictFormat*);
-extern GlyphSet (*XRenderReferenceGlyphSet_dylibloader_wrapper_xrender)( Display*, GlyphSet);
-extern void (*XRenderFreeGlyphSet_dylibloader_wrapper_xrender)( Display*, GlyphSet);
-extern void (*XRenderAddGlyphs_dylibloader_wrapper_xrender)( Display*, GlyphSet,const Glyph*,const XGlyphInfo*, int,const char*, int);
-extern void (*XRenderFreeGlyphs_dylibloader_wrapper_xrender)( Display*, GlyphSet,const Glyph*, int);
-extern void (*XRenderCompositeString8_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, GlyphSet, int, int, int, int,const char*, int);
-extern void (*XRenderCompositeString16_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, GlyphSet, int, int, int, int,const unsigned short*, int);
-extern void (*XRenderCompositeString32_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, GlyphSet, int, int, int, int,const unsigned int*, int);
-extern void (*XRenderCompositeText8_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, int, int, int, int,const XGlyphElt8*, int);
-extern void (*XRenderCompositeText16_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, int, int, int, int,const XGlyphElt16*, int);
-extern void (*XRenderCompositeText32_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, int, int, int, int,const XGlyphElt32*, int);
-extern void (*XRenderFillRectangle_dylibloader_wrapper_xrender)( Display*, int, Picture,const XRenderColor*, int, int, unsigned int, unsigned int);
-extern void (*XRenderFillRectangles_dylibloader_wrapper_xrender)( Display*, int, Picture,const XRenderColor*,const XRectangle*, int);
-extern void (*XRenderCompositeTrapezoids_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, int, int,const XTrapezoid*, int);
-extern void (*XRenderCompositeTriangles_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, int, int,const XTriangle*, int);
-extern void (*XRenderCompositeTriStrip_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, int, int,const XPointFixed*, int);
-extern void (*XRenderCompositeTriFan_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, int, int,const XPointFixed*, int);
-extern void (*XRenderCompositeDoublePoly_dylibloader_wrapper_xrender)( Display*, int, Picture, Picture,const XRenderPictFormat*, int, int, int, int,const XPointDouble*, int, int);
-extern int (*XRenderParseColor_dylibloader_wrapper_xrender)( Display*, char*, XRenderColor*);
-extern Cursor (*XRenderCreateCursor_dylibloader_wrapper_xrender)( Display*, Picture, unsigned int, unsigned int);
-extern XFilters* (*XRenderQueryFilters_dylibloader_wrapper_xrender)( Display*, Drawable);
-extern void (*XRenderSetPictureFilter_dylibloader_wrapper_xrender)( Display*, Picture,const char*, XFixed*, int);
-extern Cursor (*XRenderCreateAnimCursor_dylibloader_wrapper_xrender)( Display*, int, XAnimCursor*);
-extern void (*XRenderAddTraps_dylibloader_wrapper_xrender)( Display*, Picture, int, int,const XTrap*, int);
-extern Picture (*XRenderCreateSolidFill_dylibloader_wrapper_xrender)( Display*,const XRenderColor*);
-extern Picture (*XRenderCreateLinearGradient_dylibloader_wrapper_xrender)( Display*,const XLinearGradient*,const XFixed*,const XRenderColor*, int);
-extern Picture (*XRenderCreateRadialGradient_dylibloader_wrapper_xrender)( Display*,const XRadialGradient*,const XFixed*,const XRenderColor*, int);
-extern Picture (*XRenderCreateConicalGradient_dylibloader_wrapper_xrender)( Display*,const XConicalGradient*,const XFixed*,const XRenderColor*, int);
+extern int (*XRenderQueryExtension_dylibloader_wrapper_xrender)(Display *, int *, int *);
+extern int (*XRenderQueryVersion_dylibloader_wrapper_xrender)(Display *, int *, int *);
+extern int (*XRenderQueryFormats_dylibloader_wrapper_xrender)(Display *);
+extern int (*XRenderQuerySubpixelOrder_dylibloader_wrapper_xrender)(Display *, int);
+extern int (*XRenderSetSubpixelOrder_dylibloader_wrapper_xrender)(Display *, int, int);
+extern XRenderPictFormat *(*XRenderFindVisualFormat_dylibloader_wrapper_xrender)(Display *, const Visual *);
+extern XRenderPictFormat *(*XRenderFindFormat_dylibloader_wrapper_xrender)(Display *, unsigned long, const XRenderPictFormat *, int);
+extern XRenderPictFormat *(*XRenderFindStandardFormat_dylibloader_wrapper_xrender)(Display *, int);
+extern XIndexValue *(*XRenderQueryPictIndexValues_dylibloader_wrapper_xrender)(Display *, const XRenderPictFormat *, int *);
+extern Picture (*XRenderCreatePicture_dylibloader_wrapper_xrender)(Display *, Drawable, const XRenderPictFormat *, unsigned long, const XRenderPictureAttributes *);
+extern void (*XRenderChangePicture_dylibloader_wrapper_xrender)(Display *, Picture, unsigned long, const XRenderPictureAttributes *);
+extern void (*XRenderSetPictureClipRectangles_dylibloader_wrapper_xrender)(Display *, Picture, int, int, const XRectangle *, int);
+extern void (*XRenderSetPictureClipRegion_dylibloader_wrapper_xrender)(Display *, Picture, Region);
+extern void (*XRenderSetPictureTransform_dylibloader_wrapper_xrender)(Display *, Picture, XTransform *);
+extern void (*XRenderFreePicture_dylibloader_wrapper_xrender)(Display *, Picture);
+extern void (*XRenderComposite_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, Picture, int, int, int, int, int, int, unsigned int, unsigned int);
+extern GlyphSet (*XRenderCreateGlyphSet_dylibloader_wrapper_xrender)(Display *, const XRenderPictFormat *);
+extern GlyphSet (*XRenderReferenceGlyphSet_dylibloader_wrapper_xrender)(Display *, GlyphSet);
+extern void (*XRenderFreeGlyphSet_dylibloader_wrapper_xrender)(Display *, GlyphSet);
+extern void (*XRenderAddGlyphs_dylibloader_wrapper_xrender)(Display *, GlyphSet, const Glyph *, const XGlyphInfo *, int, const char *, int);
+extern void (*XRenderFreeGlyphs_dylibloader_wrapper_xrender)(Display *, GlyphSet, const Glyph *, int);
+extern void (*XRenderCompositeString8_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, GlyphSet, int, int, int, int, const char *, int);
+extern void (*XRenderCompositeString16_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, GlyphSet, int, int, int, int, const unsigned short *, int);
+extern void (*XRenderCompositeString32_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, GlyphSet, int, int, int, int, const unsigned int *, int);
+extern void (*XRenderCompositeText8_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, int, int, int, int, const XGlyphElt8 *, int);
+extern void (*XRenderCompositeText16_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, int, int, int, int, const XGlyphElt16 *, int);
+extern void (*XRenderCompositeText32_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, int, int, int, int, const XGlyphElt32 *, int);
+extern void (*XRenderFillRectangle_dylibloader_wrapper_xrender)(Display *, int, Picture, const XRenderColor *, int, int, unsigned int, unsigned int);
+extern void (*XRenderFillRectangles_dylibloader_wrapper_xrender)(Display *, int, Picture, const XRenderColor *, const XRectangle *, int);
+extern void (*XRenderCompositeTrapezoids_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, int, int, const XTrapezoid *, int);
+extern void (*XRenderCompositeTriangles_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, int, int, const XTriangle *, int);
+extern void (*XRenderCompositeTriStrip_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, int, int, const XPointFixed *, int);
+extern void (*XRenderCompositeTriFan_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, int, int, const XPointFixed *, int);
+extern void (*XRenderCompositeDoublePoly_dylibloader_wrapper_xrender)(Display *, int, Picture, Picture, const XRenderPictFormat *, int, int, int, int, const XPointDouble *, int, int);
+extern int (*XRenderParseColor_dylibloader_wrapper_xrender)(Display *, char *, XRenderColor *);
+extern Cursor (*XRenderCreateCursor_dylibloader_wrapper_xrender)(Display *, Picture, unsigned int, unsigned int);
+extern XFilters *(*XRenderQueryFilters_dylibloader_wrapper_xrender)(Display *, Drawable);
+extern void (*XRenderSetPictureFilter_dylibloader_wrapper_xrender)(Display *, Picture, const char *, XFixed *, int);
+extern Cursor (*XRenderCreateAnimCursor_dylibloader_wrapper_xrender)(Display *, int, XAnimCursor *);
+extern void (*XRenderAddTraps_dylibloader_wrapper_xrender)(Display *, Picture, int, int, const XTrap *, int);
+extern Picture (*XRenderCreateSolidFill_dylibloader_wrapper_xrender)(Display *, const XRenderColor *);
+extern Picture (*XRenderCreateLinearGradient_dylibloader_wrapper_xrender)(Display *, const XLinearGradient *, const XFixed *, const XRenderColor *, int);
+extern Picture (*XRenderCreateRadialGradient_dylibloader_wrapper_xrender)(Display *, const XRadialGradient *, const XFixed *, const XRenderColor *, int);
+extern Picture (*XRenderCreateConicalGradient_dylibloader_wrapper_xrender)(Display *, const XConicalGradient *, const XFixed *, const XRenderColor *, int);
int initialize_xrender(int verbose);
#ifdef __cplusplus
}
diff --git a/platform/macos/SCsub b/platform/macos/SCsub
index 3924e79fb6..598444ae24 100644
--- a/platform/macos/SCsub
+++ b/platform/macos/SCsub
@@ -27,7 +27,9 @@ def generate_bundle(target, source, env):
target_bin = lipo(bin_dir + "/" + prefix, env.extra_suffix + env.module_version_string)
# Assemble .app bundle and update version info.
- app_dir = Dir("#bin/" + (prefix + env.extra_suffix + env.module_version_string).replace(".", "_") + ".app").abspath
+ app_dir = Dir(
+ "#bin/" + (prefix + env.extra_suffix + env.module_version_string).replace(".", "_") + ".app"
+ ).abspath
templ = Dir("#misc/dist/macos_tools.app").abspath
if os.path.exists(app_dir):
shutil.rmtree(app_dir)
diff --git a/platform/macos/detect.py b/platform/macos/detect.py
index cab91fd33c..3575e93c68 100644
--- a/platform/macos/detect.py
+++ b/platform/macos/detect.py
@@ -2,7 +2,7 @@ import os
import sys
from typing import TYPE_CHECKING
-from methods import detect_darwin_sdk_path, get_compiler_version, is_vanilla_clang, print_error, print_warning
+from methods import detect_darwin_sdk_path, get_compiler_version, is_apple_clang, print_error, print_warning
from platform_methods import detect_arch, detect_mvk, validate_arch
if TYPE_CHECKING:
@@ -101,10 +101,9 @@ def configure(env: "SConsEnvironment"):
cc_version = get_compiler_version(env)
cc_version_major = cc_version["apple_major"]
cc_version_minor = cc_version["apple_minor"]
- vanilla = is_vanilla_clang(env)
# Workaround for Xcode 15 linker bug.
- if not vanilla and cc_version_major == 1500 and cc_version_minor == 0:
+ if is_apple_clang(env) and cc_version_major == 1500 and cc_version_minor == 0:
env.Prepend(LINKFLAGS=["-ld_classic"])
env.Append(CCFLAGS=["-fobjc-arc"])
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp
index bf5645d9a6..b9f9d8d613 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -970,7 +970,7 @@ Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_pres
return Error::FAILED;
} else {
print_verbose("rcodesign (" + p_path + "):\n" + str);
- int next_nl = str.find("\n", rq_offset);
+ int next_nl = str.find_char('\n', rq_offset);
String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 23, -1) : str.substr(rq_offset + 23, next_nl - rq_offset - 23);
add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), vformat(TTR("Notarization request UUID: \"%s\""), request_uuid));
add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("The notarization process generally takes less than an hour."));
@@ -1054,7 +1054,7 @@ Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_pres
return Error::FAILED;
} else {
print_verbose("notarytool (" + p_path + "):\n" + str);
- int next_nl = str.find("\n", rq_offset);
+ int next_nl = str.find_char('\n', rq_offset);
String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 4, -1) : str.substr(rq_offset + 4, next_nl - rq_offset - 4);
add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), vformat(TTR("Notarization request UUID: \"%s\""), request_uuid));
add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("The notarization process generally takes less than an hour."));
diff --git a/platform/macos/godot_open_save_delegate.mm b/platform/macos/godot_open_save_delegate.mm
index 6ffd939545..0d6bfa0c53 100644
--- a/platform/macos/godot_open_save_delegate.mm
+++ b/platform/macos/godot_open_save_delegate.mm
@@ -130,7 +130,7 @@
}
if ([type_filters count] > 0) {
- NSString *name_str = [NSString stringWithUTF8String:((tokens.size() == 1) ? tokens[0] : vformat("%s (%s)", tokens[1].strip_edges(), tokens[0].strip_edges())).utf8().get_data()];
+ NSString *name_str = [NSString stringWithUTF8String:((tokens.size() == 1) ? tokens[0] : tokens[1].strip_edges()).utf8().get_data()];
[new_allowed_types addObject:type_filters];
[popup addItemWithTitle:name_str];
}
diff --git a/platform/macos/os_macos.h b/platform/macos/os_macos.h
index 303fc112bf..4fb4507837 100644
--- a/platform/macos/os_macos.h
+++ b/platform/macos/os_macos.h
@@ -114,6 +114,8 @@ public:
virtual String get_unique_id() const override;
virtual String get_processor_name() const override;
+ virtual String get_model_name() const override;
+
virtual bool is_sandboxed() const override;
virtual Vector<String> get_granted_permissions() const override;
virtual void revoke_granted_permissions() override;
diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm
index d9086b8c38..08ff391aab 100644
--- a/platform/macos/os_macos.mm
+++ b/platform/macos/os_macos.mm
@@ -67,6 +67,15 @@ void OS_MacOS::initialize() {
initialize_core();
}
+String OS_MacOS::get_model_name() const {
+ char buffer[256];
+ size_t buffer_len = 256;
+ if (sysctlbyname("hw.model", &buffer, &buffer_len, nullptr, 0) == 0 && buffer_len != 0) {
+ return String::utf8(buffer, buffer_len);
+ }
+ return OS_Unix::get_model_name();
+}
+
String OS_MacOS::get_processor_name() const {
char buffer[256];
size_t buffer_len = 256;
diff --git a/platform/web/SCsub b/platform/web/SCsub
index b30bf20f26..9a2eea9e07 100644
--- a/platform/web/SCsub
+++ b/platform/web/SCsub
@@ -27,9 +27,11 @@ web_files = [
"javascript_bridge_singleton.cpp",
"web_main.cpp",
"os_web.cpp",
- "api/web_tools_editor_plugin.cpp",
]
+if env["target"] == "editor":
+ env.add_source_files(web_files, "editor/*.cpp")
+
sys_env = env.Clone()
sys_env.AddJSLibraries(
[
@@ -59,7 +61,7 @@ for ext in sys_env["JS_EXTERNS"]:
sys_env["ENV"]["EMCC_CLOSURE_ARGS"] += " --externs " + ext.abspath
build = []
-build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm", "#bin/godot${PROGSUFFIX}.worker.js"]
+build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
if env["dlink_enabled"]:
# Reset libraries. The main runtime will only link emscripten libraries, not godot ones.
sys_env["LIBS"] = []
@@ -108,6 +110,5 @@ js_wrapped = env.Textfile("#bin/godot", [env.File(f) for f in wrap_list], TEXTFI
# 0 - unwrapped js file (use wrapped one instead)
# 1 - wasm file
-# 2 - worker file
-# 3 - wasm side (when dlink is enabled).
-env.CreateTemplateZip(js_wrapped, build[1], build[2], build[3] if len(build) > 3 else None)
+# 2 - wasm side (when dlink is enabled).
+env.CreateTemplateZip(js_wrapped, build[1], build[2] if len(build) > 2 else None)
diff --git a/platform/web/api/api.cpp b/platform/web/api/api.cpp
index 40417bde7e..f9c1f0fd91 100644
--- a/platform/web/api/api.cpp
+++ b/platform/web/api/api.cpp
@@ -31,14 +31,12 @@
#include "api.h"
#include "javascript_bridge_singleton.h"
-#include "web_tools_editor_plugin.h"
#include "core/config/engine.h"
static JavaScriptBridge *javascript_bridge_singleton;
void register_web_api() {
- WebToolsEditorPlugin::initialize();
GDREGISTER_ABSTRACT_CLASS(JavaScriptObject);
GDREGISTER_ABSTRACT_CLASS(JavaScriptBridge);
javascript_bridge_singleton = memnew(JavaScriptBridge);
diff --git a/platform/web/detect.py b/platform/web/detect.py
index 26bbbccffa..25a5bbe5a5 100644
--- a/platform/web/detect.py
+++ b/platform/web/detect.py
@@ -201,7 +201,7 @@ def configure(env: "SConsEnvironment"):
sys.exit(255)
env.Prepend(CPPPATH=["#platform/web"])
- env.Append(CPPDEFINES=["WEB_ENABLED", "UNIX_ENABLED"])
+ env.Append(CPPDEFINES=["WEB_ENABLED", "UNIX_ENABLED", "UNIX_SOCKET_UNAVAILABLE"])
if env["opengl3"]:
env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"])
diff --git a/platform/web/doc_classes/EditorExportPlatformWeb.xml b/platform/web/doc_classes/EditorExportPlatformWeb.xml
index 755308de9a..955e3a0232 100644
--- a/platform/web/doc_classes/EditorExportPlatformWeb.xml
+++ b/platform/web/doc_classes/EditorExportPlatformWeb.xml
@@ -60,15 +60,15 @@
</member>
<member name="progressive_web_app/icon_144x144" type="String" setter="" getter="">
File path to the smallest icon for this web application. If not defined, defaults to the project icon.
- [b]Note:[/b] If the icon is not 144x144, it will be automatically resized for the final build.
+ [b]Note:[/b] If the icon is not 144×144, it will be automatically resized for the final build.
</member>
<member name="progressive_web_app/icon_180x180" type="String" setter="" getter="">
File path to the small icon for this web application. If not defined, defaults to the project icon.
- [b]Note:[/b] If the icon is not 180x180, it will be automatically resized for the final build.
+ [b]Note:[/b] If the icon is not 180×180, it will be automatically resized for the final build.
</member>
<member name="progressive_web_app/icon_512x512" type="String" setter="" getter="">
- File path to the smallest icon for this web application. If not defined, defaults to the project icon.
- [b]Note:[/b] If the icon is not 512x512, it will be automatically resized for the final build.
+ File path to the largest icon for this web application. If not defined, defaults to the project icon.
+ [b]Note:[/b] If the icon is not 512×512, it will be automatically resized for the final build.
</member>
<member name="progressive_web_app/offline_page" type="String" setter="" getter="">
The page to display, should the server hosting the page not be available. This page is saved in the client's machine.
diff --git a/platform/web/api/web_tools_editor_plugin.cpp b/platform/web/editor/web_tools_editor_plugin.cpp
index d39773bde2..a98d45a49a 100644
--- a/platform/web/api/web_tools_editor_plugin.cpp
+++ b/platform/web/editor/web_tools_editor_plugin.cpp
@@ -30,8 +30,6 @@
#include "web_tools_editor_plugin.h"
-#if defined(TOOLS_ENABLED) && defined(WEB_ENABLED)
-
#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/io/dir_access.h"
@@ -80,7 +78,7 @@ void WebToolsEditorPlugin::_download_zip() {
const String output_path = String("/tmp").path_join(output_name);
zipFile zip = zipOpen2(output_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io);
- const String base_path = resource_path.substr(0, resource_path.rfind("/")) + "/";
+ const String base_path = resource_path.substr(0, resource_path.rfind_char('/')) + "/";
_zip_recursive(resource_path, base_path, zip);
zipClose(zip, nullptr);
{
@@ -155,5 +153,3 @@ void WebToolsEditorPlugin::_zip_recursive(String p_path, String p_base_path, zip
cur = dir->get_next();
}
}
-
-#endif // TOOLS_ENABLED && WEB_ENABLED
diff --git a/platform/web/api/web_tools_editor_plugin.h b/platform/web/editor/web_tools_editor_plugin.h
index 2902f60f24..70b47ab49c 100644
--- a/platform/web/api/web_tools_editor_plugin.h
+++ b/platform/web/editor/web_tools_editor_plugin.h
@@ -31,8 +31,6 @@
#ifndef WEB_TOOLS_EDITOR_PLUGIN_H
#define WEB_TOOLS_EDITOR_PLUGIN_H
-#if defined(TOOLS_ENABLED) && defined(WEB_ENABLED)
-
#include "core/io/zip_io.h"
#include "editor/plugins/editor_plugin.h"
@@ -57,6 +55,4 @@ public:
static void initialize() {}
};
-#endif // TOOLS_ENABLED && WEB_ENABLED
-
#endif // WEB_TOOLS_EDITOR_PLUGIN_H
diff --git a/platform/web/emscripten_helpers.py b/platform/web/emscripten_helpers.py
index 3122271a71..aca5d4ecba 100644
--- a/platform/web/emscripten_helpers.py
+++ b/platform/web/emscripten_helpers.py
@@ -30,7 +30,7 @@ def create_engine_file(env, target, source, externs, threads_enabled):
return env.Substfile(target=target, source=[env.File(s) for s in source], SUBST_DICT=subst_dict)
-def create_template_zip(env, js, wasm, worker, side):
+def create_template_zip(env, js, wasm, side):
binary_name = "godot.editor" if env.editor_build else "godot"
zip_dir = env.Dir(env.GetTemplateZipPath())
in_files = [
@@ -45,9 +45,6 @@ def create_template_zip(env, js, wasm, worker, side):
zip_dir.File(binary_name + ".audio.worklet.js"),
zip_dir.File(binary_name + ".audio.position.worklet.js"),
]
- if env["threads"]:
- in_files.append(worker)
- out_files.append(zip_dir.File(binary_name + ".worker.js"))
# Dynamic linking (extensions) specific.
if env["dlink_enabled"]:
in_files.append(side) # Side wasm (contains the actual Godot code).
@@ -66,8 +63,6 @@ def create_template_zip(env, js, wasm, worker, side):
"logo.svg",
"favicon.png",
]
- if env["threads"]:
- cache.append("godot.editor.worker.js")
opt_cache = ["godot.editor.wasm"]
subst_dict = {
"___GODOT_VERSION___": get_build_version(False),
diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp
index efe3c95496..9e60a76fdc 100644
--- a/platform/web/export/export_plugin.cpp
+++ b/platform/web/export/export_plugin.cpp
@@ -169,6 +169,7 @@ void EditorExportPlatformWeb::_fix_html(Vector<uint8_t> &p_html, const Ref<Edito
replaces["$GODOT_PROJECT_NAME"] = GLOBAL_GET("application/config/name");
replaces["$GODOT_HEAD_INCLUDE"] = head_include + custom_head_include;
replaces["$GODOT_CONFIG"] = str_config;
+ replaces["$GODOT_SPLASH_COLOR"] = "#" + Color(GLOBAL_GET("application/boot_splash/bg_color")).to_html(false);
replaces["$GODOT_SPLASH"] = p_name + ".png";
if (p_preset->get("variant/thread_support")) {
@@ -214,9 +215,6 @@ Error EditorExportPlatformWeb::_add_manifest_icon(const String &p_path, const St
}
Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_preset, const String p_path, const Vector<SharedObject> &p_shared_objects) {
- List<String> preset_features;
- get_preset_features(p_preset, &preset_features);
-
String proj_name = GLOBAL_GET("application/config/name");
if (proj_name.is_empty()) {
proj_name = "Godot Game";
@@ -243,9 +241,6 @@ Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_prese
cache_files.push_back(name + ".apple-touch-icon.png");
}
- if (preset_features.find("threads")) {
- cache_files.push_back(name + ".worker.js");
- }
cache_files.push_back(name + ".audio.worklet.js");
cache_files.push_back(name + ".audio.position.worklet.js");
replaces["___GODOT_CACHE___"] = Variant(cache_files).to_json_string();
@@ -839,7 +834,6 @@ Error EditorExportPlatformWeb::_export_project(const Ref<EditorExportPreset> &p_
DirAccess::remove_file_or_error(basepath + ".html");
DirAccess::remove_file_or_error(basepath + ".offline.html");
DirAccess::remove_file_or_error(basepath + ".js");
- DirAccess::remove_file_or_error(basepath + ".worker.js");
DirAccess::remove_file_or_error(basepath + ".audio.worklet.js");
DirAccess::remove_file_or_error(basepath + ".audio.position.worklet.js");
DirAccess::remove_file_or_error(basepath + ".service.worker.js");
diff --git a/platform/web/js/engine/config.js b/platform/web/js/engine/config.js
index 61b488cf81..3947195fa1 100644
--- a/platform/web/js/engine/config.js
+++ b/platform/web/js/engine/config.js
@@ -295,8 +295,6 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused-
'locateFile': function (path) {
if (!path.startsWith('godot.')) {
return path;
- } else if (path.endsWith('.worker.js')) {
- return `${loadPath}.worker.js`;
} else if (path.endsWith('.audio.worklet.js')) {
return `${loadPath}.audio.worklet.js`;
} else if (path.endsWith('.audio.position.worklet.js')) {
diff --git a/platform/web/js/engine/engine.js b/platform/web/js/engine/engine.js
index 04c4c44c5e..1aeeb62f18 100644
--- a/platform/web/js/engine/engine.js
+++ b/platform/web/js/engine/engine.js
@@ -241,7 +241,11 @@ const Engine = (function () {
*/
installServiceWorker: function () {
if (this.config.serviceWorker && 'serviceWorker' in navigator) {
- return navigator.serviceWorker.register(this.config.serviceWorker);
+ try {
+ return navigator.serviceWorker.register(this.config.serviceWorker);
+ } catch (e) {
+ return Promise.reject(e);
+ }
}
return Promise.resolve();
},
diff --git a/platform/web/js/libs/library_godot_input.js b/platform/web/js/libs/library_godot_input.js
index 6e3b97023d..8134631f1b 100644
--- a/platform/web/js/libs/library_godot_input.js
+++ b/platform/web/js/libs/library_godot_input.js
@@ -38,41 +38,57 @@ const GodotIME = {
$GodotIME: {
ime: null,
active: false,
+ focusTimerIntervalId: -1,
getModifiers: function (evt) {
return (evt.shiftKey + 0) + ((evt.altKey + 0) << 1) + ((evt.ctrlKey + 0) << 2) + ((evt.metaKey + 0) << 3);
},
ime_active: function (active) {
- function focus_timer() {
- GodotIME.active = true;
- GodotIME.ime.focus();
+ function clearFocusTimerInterval() {
+ clearInterval(GodotIME.focusTimerIntervalId);
+ GodotIME.focusTimerIntervalId = -1;
}
- if (GodotIME.ime) {
- if (active) {
- GodotIME.ime.style.display = 'block';
- setInterval(focus_timer, 100);
- } else {
- GodotIME.ime.style.display = 'none';
- GodotConfig.canvas.focus();
- GodotIME.active = false;
+ function focusTimer() {
+ if (GodotIME.ime == null) {
+ clearFocusTimerInterval();
+ return;
}
+ GodotIME.ime.focus();
+ }
+
+ if (GodotIME.focusTimerIntervalId > -1) {
+ clearFocusTimerInterval();
+ }
+
+ if (GodotIME.ime == null) {
+ return;
+ }
+
+ GodotIME.active = active;
+ if (active) {
+ GodotIME.ime.style.display = 'block';
+ GodotIME.focusTimerIntervalId = setInterval(focusTimer, 100);
+ } else {
+ GodotIME.ime.style.display = 'none';
+ GodotConfig.canvas.focus();
}
},
ime_position: function (x, y) {
- if (GodotIME.ime) {
- const canvas = GodotConfig.canvas;
- const rect = canvas.getBoundingClientRect();
- const rw = canvas.width / rect.width;
- const rh = canvas.height / rect.height;
- const clx = (x / rw) + rect.x;
- const cly = (y / rh) + rect.y;
-
- GodotIME.ime.style.left = `${clx}px`;
- GodotIME.ime.style.top = `${cly}px`;
+ if (GodotIME.ime == null) {
+ return;
}
+ const canvas = GodotConfig.canvas;
+ const rect = canvas.getBoundingClientRect();
+ const rw = canvas.width / rect.width;
+ const rh = canvas.height / rect.height;
+ const clx = (x / rw) + rect.x;
+ const cly = (y / rh) + rect.y;
+
+ GodotIME.ime.style.left = `${clx}px`;
+ GodotIME.ime.style.top = `${cly}px`;
},
init: function (ime_cb, key_cb, code, key) {
@@ -84,20 +100,27 @@ const GodotIME = {
evt.preventDefault();
}
function ime_event_cb(event) {
- if (GodotIME.ime) {
- if (event.type === 'compositionstart') {
- ime_cb(0, null);
- GodotIME.ime.innerHTML = '';
- } else if (event.type === 'compositionupdate') {
- const ptr = GodotRuntime.allocString(event.data);
- ime_cb(1, ptr);
- GodotRuntime.free(ptr);
- } else if (event.type === 'compositionend') {
- const ptr = GodotRuntime.allocString(event.data);
- ime_cb(2, ptr);
- GodotRuntime.free(ptr);
- GodotIME.ime.innerHTML = '';
- }
+ if (GodotIME.ime == null) {
+ return;
+ }
+ switch (event.type) {
+ case 'compositionstart':
+ ime_cb(0, null);
+ GodotIME.ime.innerHTML = '';
+ break;
+ case 'compositionupdate': {
+ const ptr = GodotRuntime.allocString(event.data);
+ ime_cb(1, ptr);
+ GodotRuntime.free(ptr);
+ } break;
+ case 'compositionend': {
+ const ptr = GodotRuntime.allocString(event.data);
+ ime_cb(2, ptr);
+ GodotRuntime.free(ptr);
+ GodotIME.ime.innerHTML = '';
+ } break;
+ default:
+ // Do nothing.
}
}
@@ -133,10 +156,15 @@ const GodotIME = {
},
clear: function () {
- if (GodotIME.ime) {
- GodotIME.ime.remove();
- GodotIME.ime = null;
+ if (GodotIME.ime == null) {
+ return;
+ }
+ if (GodotIME.focusTimerIntervalId > -1) {
+ clearInterval(GodotIME.focusTimerIntervalId);
+ GodotIME.focusTimerIntervalId = -1;
}
+ GodotIME.ime.remove();
+ GodotIME.ime = null;
},
},
};
diff --git a/platform/web/js/libs/library_godot_os.js b/platform/web/js/libs/library_godot_os.js
index 568212275b..2899d7e45f 100644
--- a/platform/web/js/libs/library_godot_os.js
+++ b/platform/web/js/libs/library_godot_os.js
@@ -441,8 +441,12 @@ const GodotPWA = {
godot_js_pwa_cb__sig: 'vi',
godot_js_pwa_cb: function (p_update_cb) {
if ('serviceWorker' in navigator) {
- const cb = GodotRuntime.get_func(p_update_cb);
- navigator.serviceWorker.getRegistration().then(GodotPWA.updateState.bind(null, cb));
+ try {
+ const cb = GodotRuntime.get_func(p_update_cb);
+ navigator.serviceWorker.getRegistration().then(GodotPWA.updateState.bind(null, cb));
+ } catch (e) {
+ GodotRuntime.error('Failed to assign PWA callback', e);
+ }
}
},
@@ -450,12 +454,17 @@ const GodotPWA = {
godot_js_pwa_update__sig: 'i',
godot_js_pwa_update: function () {
if ('serviceWorker' in navigator && GodotPWA.hasUpdate) {
- navigator.serviceWorker.getRegistration().then(function (reg) {
- if (!reg || !reg.waiting) {
- return;
- }
- reg.waiting.postMessage('update');
- });
+ try {
+ navigator.serviceWorker.getRegistration().then(function (reg) {
+ if (!reg || !reg.waiting) {
+ return;
+ }
+ reg.waiting.postMessage('update');
+ });
+ } catch (e) {
+ GodotRuntime.error(e);
+ return 1;
+ }
return 0;
}
return 1;
diff --git a/platform/web/package-lock.json b/platform/web/package-lock.json
index a2e0fd3b27..7947fb96e4 100644
--- a/platform/web/package-lock.json
+++ b/platform/web/package-lock.json
@@ -9,14 +9,14 @@
"version": "1.0.0",
"license": "MIT",
"devDependencies": {
- "@eslint/js": "^9.3.0",
- "@html-eslint/eslint-plugin": "^0.24.1",
- "@html-eslint/parser": "^0.24.1",
- "@stylistic/eslint-plugin": "^2.1.0",
- "eslint": "^9.3.0",
+ "@eslint/js": "^9.12.0",
+ "@html-eslint/eslint-plugin": "^0.27.0",
+ "@html-eslint/parser": "^0.27.0",
+ "@stylistic/eslint-plugin": "^2.9.0",
+ "eslint": "^9.12.0",
"eslint-plugin-html": "^8.1.1",
"espree": "^10.0.1",
- "globals": "^15.3.0",
+ "globals": "^15.9.0",
"jsdoc": "^4.0.3"
}
},
@@ -60,14 +60,40 @@
}
},
"node_modules/@eslint-community/regexpp": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz",
- "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==",
+ "version": "4.12.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
+ "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
}
},
+ "node_modules/@eslint/config-array": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz",
+ "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/object-schema": "^2.1.4",
+ "debug": "^4.3.1",
+ "minimatch": "^3.1.2"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/core": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.6.0.tgz",
+ "integrity": "sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
"node_modules/@eslint/eslintrc": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz",
@@ -104,28 +130,54 @@
}
},
"node_modules/@eslint/js": {
- "version": "9.3.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.3.0.tgz",
- "integrity": "sha512-niBqk8iwv96+yuTwjM6bWg8ovzAPF9qkICsGtcoa5/dmqcEMfdwNAX7+/OHcJHc7wj7XqPxH98oAHytFYlw6Sw==",
+ "version": "9.12.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.12.0.tgz",
+ "integrity": "sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==",
"dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/object-schema": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz",
+ "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
+ "node_modules/@eslint/plugin-kit": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.1.tgz",
+ "integrity": "sha512-HFZ4Mp26nbWk9d/BpvP0YNL6W4UoZF0VFcTw/aPPA8RpOxeFQgK+ClABGgAUXs9Y/RGX/l1vOmrqz1MQt9MNuw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "levn": "^0.4.1"
+ },
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@html-eslint/eslint-plugin": {
- "version": "0.24.1",
- "resolved": "https://registry.npmjs.org/@html-eslint/eslint-plugin/-/eslint-plugin-0.24.1.tgz",
- "integrity": "sha512-JwNDQBrNIWEPcxgSpla/2jaUXyQCqL7Xp8CmON4Bk5qg8MwiDLXOgjylfVC+tN52i8JeHWMca34I9DqBGRj9Qg==",
+ "version": "0.27.0",
+ "resolved": "https://registry.npmjs.org/@html-eslint/eslint-plugin/-/eslint-plugin-0.27.0.tgz",
+ "integrity": "sha512-aAF14sgDKidMCCQpJ4kIhe+fwyAaAbvDlgVTIgd99F+HOWxokTTXDt39a3gewMBo76IeEHDaoizUDJQ/Vc7Mdg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@html-eslint/parser": {
- "version": "0.24.1",
- "resolved": "https://registry.npmjs.org/@html-eslint/parser/-/parser-0.24.1.tgz",
- "integrity": "sha512-O13xX/+Ldh0P7VZMpDDYc3XtWiE1cYm5QhVJ0VB5i7D8Q69HrrGN+5BjS17vkCoLTz+3zWWIiJv4oFmyS5LReA==",
+ "version": "0.27.0",
+ "resolved": "https://registry.npmjs.org/@html-eslint/parser/-/parser-0.27.0.tgz",
+ "integrity": "sha512-F/A1M0jnDAYoRvJiiSC7pIBD9DAsf4EhbndbvEi81aozD/wI8WWXON50xZPUaGHCI1C+2syTVifxDz8MvDKaQA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"es-html-parser": "^0.0.9"
},
@@ -133,18 +185,28 @@
"node": ">=8.10.0"
}
},
- "node_modules/@humanwhocodes/config-array": {
- "version": "0.13.0",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
- "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
+ "node_modules/@humanfs/core": {
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.0.tgz",
+ "integrity": "sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==",
"dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanfs/node": {
+ "version": "0.16.5",
+ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.5.tgz",
+ "integrity": "sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==",
+ "dev": true,
+ "license": "Apache-2.0",
"dependencies": {
- "@humanwhocodes/object-schema": "^2.0.3",
- "debug": "^4.3.1",
- "minimatch": "^3.0.5"
+ "@humanfs/core": "^0.19.0",
+ "@humanwhocodes/retry": "^0.3.0"
},
"engines": {
- "node": ">=10.10.0"
+ "node": ">=18.18.0"
}
},
"node_modules/@humanwhocodes/module-importer": {
@@ -160,17 +222,12 @@
"url": "https://github.com/sponsors/nzakas"
}
},
- "node_modules/@humanwhocodes/object-schema": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
- "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
- "dev": true
- },
"node_modules/@humanwhocodes/retry": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz",
- "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==",
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz",
+ "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
"node": ">=18.18"
},
@@ -227,50 +284,15 @@
}
},
"node_modules/@stylistic/eslint-plugin": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.1.0.tgz",
- "integrity": "sha512-cBBowKP2u/+uE5CzgH5w8pE9VKqcM7BXdIDPIbGt2rmLJGnA6MJPr9vYGaqgMoJFs7R/FzsMQerMvvEP40g2uw==",
- "dev": true,
- "dependencies": {
- "@stylistic/eslint-plugin-js": "2.1.0",
- "@stylistic/eslint-plugin-jsx": "2.1.0",
- "@stylistic/eslint-plugin-plus": "2.1.0",
- "@stylistic/eslint-plugin-ts": "2.1.0",
- "@types/eslint": "^8.56.10"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "peerDependencies": {
- "eslint": ">=8.40.0"
- }
- },
- "node_modules/@stylistic/eslint-plugin-js": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.1.0.tgz",
- "integrity": "sha512-gdXUjGNSsnY6nPyqxu6lmDTtVrwCOjun4x8PUn0x04d5ucLI74N3MT1Q0UhdcOR9No3bo5PGDyBgXK+KmD787A==",
- "dev": true,
- "dependencies": {
- "@types/eslint": "^8.56.10",
- "acorn": "^8.11.3",
- "eslint-visitor-keys": "^4.0.0",
- "espree": "^10.0.1"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "peerDependencies": {
- "eslint": ">=8.40.0"
- }
- },
- "node_modules/@stylistic/eslint-plugin-jsx": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-2.1.0.tgz",
- "integrity": "sha512-mMD7S+IndZo2vxmwpHVTCwx2O1VdtE5tmpeNwgaEcXODzWV1WTWpnsc/PECQKIr/mkLPFWiSIqcuYNhQ/3l6AQ==",
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.9.0.tgz",
+ "integrity": "sha512-OrDyFAYjBT61122MIY1a3SfEgy3YCMgt2vL4eoPmvTwDBwyQhAXurxNQznlRD/jESNfYWfID8Ej+31LljvF7Xg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@stylistic/eslint-plugin-js": "^2.1.0",
- "@types/eslint": "^8.56.10",
+ "@typescript-eslint/utils": "^8.8.0",
+ "eslint-visitor-keys": "^4.1.0",
+ "espree": "^10.2.0",
"estraverse": "^5.3.0",
"picomatch": "^4.0.2"
},
@@ -281,101 +303,19 @@
"eslint": ">=8.40.0"
}
},
- "node_modules/@stylistic/eslint-plugin-plus": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.1.0.tgz",
- "integrity": "sha512-S5QAlgYXESJaSBFhBSBLZy9o36gXrXQwWSt6QkO+F0SrT9vpV5JF/VKoh+ojO7tHzd8Ckmyouq02TT9Sv2B0zQ==",
- "dev": true,
- "dependencies": {
- "@types/eslint": "^8.56.10",
- "@typescript-eslint/utils": "^7.8.0"
- },
- "peerDependencies": {
- "eslint": "*"
- }
- },
- "node_modules/@stylistic/eslint-plugin-plus/node_modules/@typescript-eslint/utils": {
- "version": "7.10.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.10.0.tgz",
- "integrity": "sha512-olzif1Fuo8R8m/qKkzJqT7qwy16CzPRWBvERS0uvyc+DHd8AKbO4Jb7kpAvVzMmZm8TrHnI7hvjN4I05zow+tg==",
- "dev": true,
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.4.0",
- "@typescript-eslint/scope-manager": "7.10.0",
- "@typescript-eslint/types": "7.10.0",
- "@typescript-eslint/typescript-estree": "7.10.0"
- },
- "engines": {
- "node": "^18.18.0 || >=20.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.56.0"
- }
- },
- "node_modules/@stylistic/eslint-plugin-ts": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.1.0.tgz",
- "integrity": "sha512-2ioFibufHYBALx2TBrU4KXovCkN8qCqcb9yIHc0fyOfTaO5jw4d56WW7YRcF3Zgde6qFyXwAN6z/+w4pnmos1g==",
- "dev": true,
- "dependencies": {
- "@stylistic/eslint-plugin-js": "2.1.0",
- "@types/eslint": "^8.56.10",
- "@typescript-eslint/utils": "^7.8.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "peerDependencies": {
- "eslint": ">=8.40.0"
- }
- },
- "node_modules/@stylistic/eslint-plugin-ts/node_modules/@typescript-eslint/utils": {
- "version": "7.10.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.10.0.tgz",
- "integrity": "sha512-olzif1Fuo8R8m/qKkzJqT7qwy16CzPRWBvERS0uvyc+DHd8AKbO4Jb7kpAvVzMmZm8TrHnI7hvjN4I05zow+tg==",
- "dev": true,
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.4.0",
- "@typescript-eslint/scope-manager": "7.10.0",
- "@typescript-eslint/types": "7.10.0",
- "@typescript-eslint/typescript-estree": "7.10.0"
- },
- "engines": {
- "node": "^18.18.0 || >=20.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.56.0"
- }
- },
- "node_modules/@types/eslint": {
- "version": "8.56.10",
- "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz",
- "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==",
- "dev": true,
- "dependencies": {
- "@types/estree": "*",
- "@types/json-schema": "*"
- }
- },
"node_modules/@types/estree": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
- "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
- "dev": true
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+ "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@types/json-schema": {
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@types/linkify-it": {
"version": "5.0.0",
@@ -400,16 +340,17 @@
"dev": true
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "7.10.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.10.0.tgz",
- "integrity": "sha512-7L01/K8W/VGl7noe2mgH0K7BE29Sq6KAbVmxurj8GGaPDZXPr8EEQ2seOeAS+mEV9DnzxBQB6ax6qQQ5C6P4xg==",
+ "version": "8.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.11.0.tgz",
+ "integrity": "sha512-Uholz7tWhXmA4r6epo+vaeV7yjdKy5QFCERMjs1kMVsLRKIrSdM6o21W2He9ftp5PP6aWOVpD5zvrvuHZC0bMQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "7.10.0",
- "@typescript-eslint/visitor-keys": "7.10.0"
+ "@typescript-eslint/types": "8.11.0",
+ "@typescript-eslint/visitor-keys": "8.11.0"
},
"engines": {
- "node": "^18.18.0 || >=20.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
@@ -417,12 +358,13 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "7.10.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.10.0.tgz",
- "integrity": "sha512-7fNj+Ya35aNyhuqrA1E/VayQX9Elwr8NKZ4WueClR3KwJ7Xx9jcCdOrLW04h51de/+gNbyFMs+IDxh5xIwfbNg==",
+ "version": "8.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.11.0.tgz",
+ "integrity": "sha512-tn6sNMHf6EBAYMvmPUaKaVeYvhUsrE6x+bXQTxjQRp360h1giATU0WvgeEys1spbvb5R+VpNOZ+XJmjD8wOUHw==",
"dev": true,
+ "license": "MIT",
"engines": {
- "node": "^18.18.0 || >=20.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
@@ -430,22 +372,23 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "7.10.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.10.0.tgz",
- "integrity": "sha512-LXFnQJjL9XIcxeVfqmNj60YhatpRLt6UhdlFwAkjNc6jSUlK8zQOl1oktAP8PlWFzPQC1jny/8Bai3/HPuvN5g==",
+ "version": "8.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.11.0.tgz",
+ "integrity": "sha512-yHC3s1z1RCHoCz5t06gf7jH24rr3vns08XXhfEqzYpd6Hll3z/3g23JRi0jM8A47UFKNc3u/y5KIMx8Ynbjohg==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
- "@typescript-eslint/types": "7.10.0",
- "@typescript-eslint/visitor-keys": "7.10.0",
+ "@typescript-eslint/types": "8.11.0",
+ "@typescript-eslint/visitor-keys": "8.11.0",
"debug": "^4.3.4",
- "globby": "^11.1.0",
+ "fast-glob": "^3.3.2",
"is-glob": "^4.0.3",
"minimatch": "^9.0.4",
"semver": "^7.6.0",
"ts-api-utils": "^1.3.0"
},
"engines": {
- "node": "^18.18.0 || >=20.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
@@ -462,15 +405,17 @@
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
- "version": "9.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
- "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
@@ -481,17 +426,41 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/@typescript-eslint/utils": {
+ "version": "8.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.11.0.tgz",
+ "integrity": "sha512-CYiX6WZcbXNJV7UNB4PLDIBtSdRmRI/nb0FMyqHPTQD1rMjA0foPLaPUV39C/MxkTd/QKSeX+Gb34PPsDVC35g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.4.0",
+ "@typescript-eslint/scope-manager": "8.11.0",
+ "@typescript-eslint/types": "8.11.0",
+ "@typescript-eslint/typescript-estree": "8.11.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0"
+ }
+ },
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "7.10.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.10.0.tgz",
- "integrity": "sha512-9ntIVgsi6gg6FIq9xjEO4VQJvwOqA3jaBFQJ/6TK5AvEup2+cECI6Fh7QiBxmfMHXU0V0J4RyPeOU1VDNzl9cg==",
+ "version": "8.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.11.0.tgz",
+ "integrity": "sha512-EaewX6lxSjRJnc+99+dqzTeoDZUfyrA52d2/HRrkI830kgovWsmIiTfmr0NZorzqic7ga+1bS60lRBUgR3n/Bw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "7.10.0",
+ "@typescript-eslint/types": "8.11.0",
"eslint-visitor-keys": "^3.4.3"
},
"engines": {
- "node": "^18.18.0 || >=20.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
@@ -503,6 +472,7 @@
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
@@ -511,10 +481,11 @@
}
},
"node_modules/acorn": {
- "version": "8.11.3",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
- "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
+ "version": "8.12.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
+ "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
"dev": true,
+ "license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
@@ -547,15 +518,6 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
- "node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@@ -577,15 +539,6 @@
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true
},
- "node_modules/array-union": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
- "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -613,6 +566,7 @@
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"fill-range": "^7.1.1"
},
@@ -718,18 +672,6 @@
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"dev": true
},
- "node_modules/dir-glob": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
- "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
- "dev": true,
- "dependencies": {
- "path-type": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
@@ -816,28 +758,33 @@
}
},
"node_modules/eslint": {
- "version": "9.3.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.3.0.tgz",
- "integrity": "sha512-5Iv4CsZW030lpUqHBapdPo3MJetAPtejVW8B84GIcIIv8+ohFaddXsrn1Gn8uD9ijDb+kcYKFUVmC8qG8B2ORQ==",
+ "version": "9.12.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.12.0.tgz",
+ "integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
- "@eslint-community/regexpp": "^4.6.1",
+ "@eslint-community/regexpp": "^4.11.0",
+ "@eslint/config-array": "^0.18.0",
+ "@eslint/core": "^0.6.0",
"@eslint/eslintrc": "^3.1.0",
- "@eslint/js": "9.3.0",
- "@humanwhocodes/config-array": "^0.13.0",
+ "@eslint/js": "9.12.0",
+ "@eslint/plugin-kit": "^0.2.0",
+ "@humanfs/node": "^0.16.5",
"@humanwhocodes/module-importer": "^1.0.1",
- "@humanwhocodes/retry": "^0.3.0",
- "@nodelib/fs.walk": "^1.2.8",
+ "@humanwhocodes/retry": "^0.3.1",
+ "@types/estree": "^1.0.6",
+ "@types/json-schema": "^7.0.15",
"ajv": "^6.12.4",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
"debug": "^4.3.2",
"escape-string-regexp": "^4.0.0",
- "eslint-scope": "^8.0.1",
- "eslint-visitor-keys": "^4.0.0",
- "espree": "^10.0.1",
- "esquery": "^1.4.2",
+ "eslint-scope": "^8.1.0",
+ "eslint-visitor-keys": "^4.1.0",
+ "espree": "^10.2.0",
+ "esquery": "^1.5.0",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
"file-entry-cache": "^8.0.0",
@@ -846,14 +793,11 @@
"ignore": "^5.2.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
- "is-path-inside": "^3.0.3",
"json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
"lodash.merge": "^4.6.2",
"minimatch": "^3.1.2",
"natural-compare": "^1.4.0",
"optionator": "^0.9.3",
- "strip-ansi": "^6.0.1",
"text-table": "^0.2.0"
},
"bin": {
@@ -863,7 +807,15 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
- "url": "https://opencollective.com/eslint"
+ "url": "https://eslint.org/donate"
+ },
+ "peerDependencies": {
+ "jiti": "*"
+ },
+ "peerDependenciesMeta": {
+ "jiti": {
+ "optional": true
+ }
}
},
"node_modules/eslint-plugin-html": {
@@ -879,10 +831,11 @@
}
},
"node_modules/eslint-scope": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz",
- "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==",
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz",
+ "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
@@ -895,10 +848,11 @@
}
},
"node_modules/eslint-visitor-keys": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
- "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz",
+ "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==",
"dev": true,
+ "license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
@@ -907,14 +861,15 @@
}
},
"node_modules/espree": {
- "version": "10.0.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz",
- "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==",
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz",
+ "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
- "acorn": "^8.11.3",
+ "acorn": "^8.12.0",
"acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^4.0.0"
+ "eslint-visitor-keys": "^4.1.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -940,6 +895,7 @@
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
"estraverse": "^5.2.0"
},
@@ -976,6 +932,7 @@
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
@@ -992,6 +949,7 @@
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
+ "license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
},
@@ -1037,6 +995,7 @@
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -1092,10 +1051,11 @@
}
},
"node_modules/globals": {
- "version": "15.3.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-15.3.0.tgz",
- "integrity": "sha512-cCdyVjIUVTtX8ZsPkq1oCsOsLmGIswqnjZYMJJTGaNApj1yHtLSymKhwH51ttirREn75z3p4k051clwg7rvNKA==",
+ "version": "15.9.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-15.9.0.tgz",
+ "integrity": "sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=18"
},
@@ -1103,26 +1063,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/globby": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
- "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
- "dev": true,
- "dependencies": {
- "array-union": "^2.1.0",
- "dir-glob": "^3.0.1",
- "fast-glob": "^3.2.9",
- "ignore": "^5.2.0",
- "merge2": "^1.4.1",
- "slash": "^3.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
@@ -1217,19 +1157,11 @@
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.12.0"
}
},
- "node_modules/is-path-inside": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
- "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -1430,15 +1362,17 @@
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 8"
}
},
"node_modules/micromatch": {
- "version": "4.0.7",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
- "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"braces": "^3.0.3",
"picomatch": "^2.3.1"
@@ -1452,6 +1386,7 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8.6"
},
@@ -1572,20 +1507,12 @@
"node": ">=8"
}
},
- "node_modules/path-type": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
- "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=12"
},
@@ -1692,10 +1619,11 @@
}
},
"node_modules/semver": {
- "version": "7.6.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
- "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
"dev": true,
+ "license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
@@ -1724,27 +1652,6 @@
"node": ">=8"
}
},
- "node_modules/slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -1780,6 +1687,7 @@
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
},
@@ -1792,6 +1700,7 @@
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
"integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=16"
},
@@ -1812,10 +1721,11 @@
}
},
"node_modules/typescript": {
- "version": "5.4.5",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
- "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
+ "version": "5.6.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
+ "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
"dev": true,
+ "license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
diff --git a/platform/web/package.json b/platform/web/package.json
index 588af2ff3b..bf61eb184c 100644
--- a/platform/web/package.json
+++ b/platform/web/package.json
@@ -11,14 +11,14 @@
"format": "npm run lint -- --fix"
},
"devDependencies": {
- "@eslint/js": "^9.3.0",
- "@html-eslint/eslint-plugin": "^0.24.1",
- "@html-eslint/parser": "^0.24.1",
- "@stylistic/eslint-plugin": "^2.1.0",
- "eslint": "^9.3.0",
+ "@eslint/js": "^9.12.0",
+ "@html-eslint/eslint-plugin": "^0.27.0",
+ "@html-eslint/parser": "^0.27.0",
+ "@stylistic/eslint-plugin": "^2.9.0",
+ "eslint": "^9.12.0",
"eslint-plugin-html": "^8.1.1",
"espree": "^10.0.1",
- "globals": "^15.3.0",
+ "globals": "^15.9.0",
"jsdoc": "^4.0.3"
}
}
diff --git a/platform/web/web_main.cpp b/platform/web/web_main.cpp
index d0c3bd7c0e..3487ed2ded 100644
--- a/platform/web/web_main.cpp
+++ b/platform/web/web_main.cpp
@@ -38,6 +38,10 @@
#include "scene/main/scene_tree.h"
#include "scene/main/window.h" // SceneTree only forward declares it.
+#ifdef TOOLS_ENABLED
+#include "editor/web_tools_editor_plugin.h"
+#endif
+
#include <emscripten/emscripten.h>
#include <stdlib.h>
@@ -104,6 +108,10 @@ void main_loop_callback() {
extern EMSCRIPTEN_KEEPALIVE int godot_web_main(int argc, char *argv[]) {
os = new OS_Web();
+#ifdef TOOLS_ENABLED
+ WebToolsEditorPlugin::initialize();
+#endif
+
// We must override main when testing is enabled
TEST_MAIN_OVERRIDE
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
index 30df9df809..1ddefb9c33 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -60,6 +60,9 @@ sources += res_obj
prog = env.add_program("#bin/godot", sources, PROGSUFFIX=env["PROGSUFFIX"])
arrange_program_clean(prog)
+if env.msvc:
+ env.Depends(prog, "godot.natvis")
+
# Build console wrapper app.
if env["windows_subsystem"] == "gui":
env_wrap = env.Clone()
@@ -80,16 +83,6 @@ if env["windows_subsystem"] == "gui":
env_wrap.Depends(prog_wrap, prog)
sources += common_win_wrap + res_wrap_obj
-# Microsoft Visual Studio Project Generation
-if env["vsproj"]:
- env.vs_srcs += ["platform/windows/" + res_file]
- env.vs_srcs += ["platform/windows/godot.natvis"]
- for x in common_win:
- env.vs_srcs += ["platform/windows/" + str(x)]
- if env["windows_subsystem"] == "gui":
- for x in common_win_wrap:
- env.vs_srcs += ["platform/windows/" + str(x)]
-
if env["d3d12"]:
dxc_target_aliases = {
"x86_32": "x86",
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index a6eab1bd29..ec3fcea6cb 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -505,7 +505,7 @@ void DisplayServerWindows::_thread_fd_monitor(void *p_ud) {
}
if (filter_names.is_empty()) {
filter_exts.push_back(String("*.*").utf16());
- filter_names.push_back(RTR("All Files").utf16());
+ filter_names.push_back((RTR("All Files") + " (*)").utf16());
}
Vector<COMDLG_FILTERSPEC> filters;
@@ -2167,6 +2167,10 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_initiali
r_style |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
r_style_ex |= WS_EX_ACCEPTFILES;
+
+ if (OS::get_singleton()->get_current_rendering_driver_name() == "d3d12") {
+ r_style_ex |= WS_EX_NOREDIRECTIONBITMAP;
+ }
}
void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repaint) {
@@ -3244,6 +3248,10 @@ void DisplayServerWindows::process_events() {
}
_THREAD_SAFE_UNLOCK_
+ if (tts) {
+ tts->process_events();
+ }
+
if (!drop_events) {
_process_key_events();
Input::get_singleton()->flush_buffered_events();
@@ -4792,9 +4800,12 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
break;
}
- DisplayServer::WindowID receiving_window_id = _get_focused_window_or_popup();
- if (receiving_window_id == INVALID_WINDOW_ID) {
- receiving_window_id = window_id;
+ DisplayServer::WindowID receiving_window_id = window_id;
+ if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) {
+ receiving_window_id = _get_focused_window_or_popup();
+ if (receiving_window_id == INVALID_WINDOW_ID) {
+ receiving_window_id = window_id;
+ }
}
const BitField<WinKeyModifierMask> &mods = _get_mods();
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 0462d3f8fa..8860268115 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -40,7 +40,6 @@
#include "core/input/input.h"
#include "core/io/image.h"
#include "core/os/os.h"
-#include "drivers/unix/ip_unix.h"
#include "drivers/wasapi/audio_driver_wasapi.h"
#include "drivers/winmidi/midi_driver_winmidi.h"
#include "servers/audio_server.h"
@@ -357,6 +356,10 @@ typedef enum _SHC_PROCESS_DPI_AWARENESS {
SHC_PROCESS_PER_MONITOR_DPI_AWARE = 2,
} SHC_PROCESS_DPI_AWARENESS;
+#ifndef WS_EX_NOREDIRECTIONBITMAP
+#define WS_EX_NOREDIRECTIONBITMAP 0x00200000L
+#endif
+
class DropTargetWindows;
class DisplayServerWindows : public DisplayServer {
diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis
index fc34ad3cb3..e3a535580f 100644
--- a/platform/windows/godot.natvis
+++ b/platform/windows/godot.natvis
@@ -30,16 +30,6 @@
</Expand>
</Type>
- <Type Name="TypedArray&lt;*&gt;">
- <Expand>
- <Item Name="[size]"> _p->array._cowdata._ptr ? (((const unsigned long long *)(_p->array._cowdata._ptr))[-1]) : 0</Item>
- <ArrayItems>
- <Size>_p->array._cowdata._ptr ? (((const unsigned long long *)(_p->array._cowdata._ptr))[-1]) : 0</Size>
- <ValuePointer >(Variant *) _p->array._cowdata._ptr</ValuePointer>
- </ArrayItems>
- </Expand>
- </Type>
-
<Type Name="Dictionary">
<Expand>
<Item Name="[size]">_p &amp;&amp; _p->variant_map.head_element ? _p->variant_map.num_elements : 0</Item>
@@ -153,7 +143,7 @@
<Type Name="HashMapElement&lt;*,*&gt;" IncludeView="MapHelper">
<DisplayString>{data.value}</DisplayString>
<Expand>
- <Item Name="[key]" >($T1 *) &amp;data.key</Item>
+ <Item Name="[key]">($T1 *) &amp;data.key</Item>
<Item Name="[value]">($T2 *) &amp;data.value</Item>
</Expand>
</Type>
@@ -285,39 +275,164 @@
</Type>
<Type Name="Vector2">
- <DisplayString>{{{x},{y}}}</DisplayString>
+ <DisplayString>({x,g}, {y,g})</DisplayString>
+ <Expand>
+ <Item Name="[x]">x</Item>
+ <Item Name="[y]">y</Item>
+ </Expand>
+ </Type>
+ <Type Name="Vector2i">
+ <DisplayString>({x}, {y})</DisplayString>
<Expand>
- <Item Name="x">x</Item>
- <Item Name="y">y</Item>
+ <Item Name="[x]">x</Item>
+ <Item Name="[y]">y</Item>
</Expand>
</Type>
<Type Name="Vector3">
- <DisplayString>{{{x},{y},{z}}}</DisplayString>
+ <DisplayString>({x,g}, {y,g}, {z,g})</DisplayString>
+ <Expand>
+ <Item Name="[x]">x</Item>
+ <Item Name="[y]">y</Item>
+ <Item Name="[z]">z</Item>
+ </Expand>
+ </Type>
+ <Type Name="Vector3i">
+ <DisplayString>({x}, {y}, {z})</DisplayString>
<Expand>
- <Item Name="x">x</Item>
- <Item Name="y">y</Item>
- <Item Name="z">z</Item>
+ <Item Name="[x]">x</Item>
+ <Item Name="[y]">y</Item>
+ <Item Name="[z]">z</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="Vector4">
+ <DisplayString>({x,g}, {y,g}, {z,g}, {w,g})</DisplayString>
+ <Expand>
+ <Item Name="[x]">x</Item>
+ <Item Name="[y]">y</Item>
+ <Item Name="[z]">z</Item>
+ <Item Name="[w]">w</Item>
+ </Expand>
+ </Type>
+ <Type Name="Vector4i">
+ <DisplayString>({x}, {y}, {z}, {w})</DisplayString>
+ <Expand>
+ <Item Name="[x]">x</Item>
+ <Item Name="[y]">y</Item>
+ <Item Name="[z]">z</Item>
+ <Item Name="[w]">w</Item>
</Expand>
</Type>
<Type Name="Quaternion">
- <DisplayString>Quaternion {{{x},{y},{z},{w}}}</DisplayString>
+ <DisplayString>({x,g}, {y,g}, {z,g}, {w,g})</DisplayString>
<Expand>
- <Item Name="x">x</Item>
- <Item Name="y">y</Item>
- <Item Name="z">z</Item>
- <Item Name="w">w</Item>
+ <Item Name="[x]">x</Item>
+ <Item Name="[y]">y</Item>
+ <Item Name="[z]">z</Item>
+ <Item Name="[w]">w</Item>
</Expand>
</Type>
<Type Name="Color">
- <DisplayString>Color {{{r},{g},{b},{a}}}</DisplayString>
+ <DisplayString>({r,g}, {g,g}, {b,g}, {a,g})</DisplayString>
+ <Expand>
+ <Item Name="[red]">r</Item>
+ <Item Name="[green]">g</Item>
+ <Item Name="[blue]">b</Item>
+ <Item Name="[alpha]">a</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="Rect2">
+ <DisplayString>[P: {position}, S: {size}]</DisplayString>
+ <Expand>
+ <Item Name="[position]">position,nr</Item>
+ <Item Name="[size]">size,nr</Item>
+ </Expand>
+ </Type>
+ <Type Name="Rect2i">
+ <DisplayString>[P: {position}, S: {size}]</DisplayString>
+ <Expand>
+ <Item Name="[position]">position,nr</Item>
+ <Item Name="[size]">size,nr</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="AABB">
+ <DisplayString>[P: {position}, S: {size}]</DisplayString>
+ <Expand>
+ <Item Name="[position]">position,nr</Item>
+ <Item Name="[size]">size,nr</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="Plane">
+ <DisplayString>[N: {normal}, D: {d,g}]</DisplayString>
+ <Expand>
+ <Item Name="[normal]">normal,nr</Item>
+ <Item Name="[d]">d</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="Basis">
+ <DisplayString>[X: {rows[0]}, Y: {rows[1]}, Z: {rows[2]}]</DisplayString>
+ <Expand>
+ <Item Name="[x]">rows[0],nr</Item>
+ <Item Name="[y]">rows[1],nr</Item>
+ <Item Name="[z]">rows[2],nr</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="Transform2D">
+ <DisplayString>[X: {columns[0]}, Y: {columns[1]}, O: {columns[2]}]</DisplayString>
+ <Expand>
+ <Item Name="[x]">columns[0],nr</Item>
+ <Item Name="[y]">columns[1],nr</Item>
+ <Item Name="[origin]">columns[2],nr</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="Transform3D">
+ <!-- Can't call column functions, so just pretend we can via obscene code duplication. -->
+ <DisplayString>[X: ({basis.rows[0].x,g}, {basis.rows[1].x,g}, {basis.rows[2].x,g}), Y: ({basis.rows[0].y,g}, {basis.rows[1].y,g}, {basis.rows[2].y,g}), Z: ({basis.rows[0].z,g}, {basis.rows[1].z,g}, {basis.rows[2].z,g}), O: {origin}]</DisplayString>
+ <Expand>
+ <Synthetic Name="[x]">
+ <DisplayString>({basis.rows[0].x,g}, {basis.rows[1].x,g}, {basis.rows[2].x,g})</DisplayString>
+ <Expand>
+ <Item Name="[x]">basis.rows[0].x</Item>
+ <Item Name="[y]">basis.rows[1].x</Item>
+ <Item Name="[z]">basis.rows[2].x</Item>
+ </Expand>
+ </Synthetic>
+ <Synthetic Name="[y]">
+ <DisplayString>({basis.rows[0].y,g}, {basis.rows[1].y,g}, {basis.rows[2].y,g})</DisplayString>
+ <Expand>
+ <Item Name="[x]">basis.rows[0].y</Item>
+ <Item Name="[y]">basis.rows[1].y</Item>
+ <Item Name="[z]">basis.rows[2].y</Item>
+ </Expand>
+ </Synthetic>
+ <Synthetic Name="[z]">
+ <DisplayString>({basis.rows[0].z,g}, {basis.rows[1].z,g}, {basis.rows[2].z,g})</DisplayString>
+ <Expand>
+ <Item Name="[x]">basis.rows[0].z</Item>
+ <Item Name="[y]">basis.rows[1].z</Item>
+ <Item Name="[z]">basis.rows[2].z</Item>
+ </Expand>
+ </Synthetic>
+ <Item Name="[origin]">origin,nr</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="Projection">
+ <DisplayString>[X: {columns[0]}, Y: {columns[1]}, Z: {columns[2]}, W: {columns[3]}]</DisplayString>
<Expand>
- <Item Name="red">r</Item>
- <Item Name="green">g</Item>
- <Item Name="blue">b</Item>
- <Item Name="alpha">a</Item>
+ <Item Name="[x]">columns[0],nr</Item>
+ <Item Name="[y]">columns[1],nr</Item>
+ <Item Name="[z]">columns[2],nr</Item>
+ <Item Name="[w]">columns[3],nr</Item>
</Expand>
</Type>
</AutoVisualizer>
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index bff3443214..2b5c77d4b9 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -40,10 +40,11 @@
#include "core/debugger/script_debugger.h"
#include "core/io/marshalls.h"
#include "core/version_generated.gen.h"
-#include "drivers/unix/net_socket_posix.h"
#include "drivers/windows/dir_access_windows.h"
#include "drivers/windows/file_access_windows.h"
#include "drivers/windows/file_access_windows_pipe.h"
+#include "drivers/windows/ip_windows.h"
+#include "drivers/windows/net_socket_winsock.h"
#include "main/main.h"
#include "servers/audio_server.h"
#include "servers/rendering/rendering_server_default.h"
@@ -69,6 +70,7 @@
extern "C" {
__declspec(dllexport) DWORD NvOptimusEnablement = 1;
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
+__declspec(dllexport) void NoHotPatch() {} // Disable Nahimic code injection.
}
// Workaround mingw-w64 < 4.0 bug
@@ -156,6 +158,52 @@ void RedirectIOToConsole() {
}
}
+bool OS_Windows::is_using_con_wrapper() const {
+ static String exe_renames[] = {
+ ".console.exe",
+ "_console.exe",
+ " console.exe",
+ "console.exe",
+ String(),
+ };
+
+ bool found_exe = false;
+ bool found_conwrap_exe = false;
+ String exe_name = get_executable_path().to_lower();
+ String exe_dir = exe_name.get_base_dir();
+ String exe_fname = exe_name.get_file().get_basename();
+
+ DWORD pids[256];
+ DWORD count = GetConsoleProcessList(&pids[0], 256);
+ for (DWORD i = 0; i < count; i++) {
+ HANDLE process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, pids[i]);
+ if (process != NULL) {
+ WCHAR proc_name[MAX_PATH];
+ DWORD len = MAX_PATH;
+ if (QueryFullProcessImageNameW(process, 0, &proc_name[0], &len)) {
+ String name = String::utf16((const char16_t *)&proc_name[0], len).replace("\\", "/").to_lower();
+ if (name == exe_name) {
+ found_exe = true;
+ }
+ for (int j = 0; !exe_renames[j].is_empty(); j++) {
+ if (name == exe_dir.path_join(exe_fname + exe_renames[j])) {
+ found_conwrap_exe = true;
+ }
+ }
+ }
+ CloseHandle(process);
+ if (found_conwrap_exe && found_exe) {
+ break;
+ }
+ }
+ }
+ if (!found_exe) {
+ return true; // Unable to read console info, assume true.
+ }
+
+ return found_conwrap_exe;
+}
+
BOOL WINAPI HandlerRoutine(_In_ DWORD dwCtrlType) {
if (!EngineDebugger::is_active()) {
return FALSE;
@@ -209,7 +257,7 @@ void OS_Windows::initialize() {
DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_USERDATA);
DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_FILESYSTEM);
- NetSocketPosix::make_default();
+ NetSocketWinSock::make_default();
// We need to know how often the clock is updated
QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second);
@@ -228,7 +276,7 @@ void OS_Windows::initialize() {
current_pi.pi.hProcess = GetCurrentProcess();
process_map->insert(GetCurrentProcessId(), current_pi);
- IPUnix::make_default();
+ IPWindows::make_default();
main_loop = nullptr;
HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown **>(&dwrite_factory));
@@ -303,7 +351,7 @@ void OS_Windows::finalize_core() {
timeEndPeriod(1);
memdelete(process_map);
- NetSocketPosix::cleanup();
+ NetSocketWinSock::cleanup();
#ifdef WINDOWS_DEBUG_OUTPUT_ENABLED
remove_error_handler(&error_handlers);
@@ -918,18 +966,10 @@ Dictionary OS_Windows::execute_with_pipe(const String &p_path, const List<String
sa.lpSecurityDescriptor = nullptr;
ERR_FAIL_COND_V(!CreatePipe(&pipe_in[0], &pipe_in[1], &sa, 0), ret);
- if (!SetHandleInformation(pipe_in[1], HANDLE_FLAG_INHERIT, 0)) {
- CLEAN_PIPES
- ERR_FAIL_V(ret);
- }
if (!CreatePipe(&pipe_out[0], &pipe_out[1], &sa, 0)) {
CLEAN_PIPES
ERR_FAIL_V(ret);
}
- if (!SetHandleInformation(pipe_out[0], HANDLE_FLAG_INHERIT, 0)) {
- CLEAN_PIPES
- ERR_FAIL_V(ret);
- }
if (!CreatePipe(&pipe_err[0], &pipe_err[1], &sa, 0)) {
CLEAN_PIPES
ERR_FAIL_V(ret);
@@ -939,16 +979,37 @@ Dictionary OS_Windows::execute_with_pipe(const String &p_path, const List<String
// Create process.
ProcessInfo pi;
ZeroMemory(&pi.si, sizeof(pi.si));
- pi.si.cb = sizeof(pi.si);
+ pi.si.StartupInfo.cb = sizeof(pi.si);
ZeroMemory(&pi.pi, sizeof(pi.pi));
- LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si;
+ LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si.StartupInfo;
- pi.si.dwFlags |= STARTF_USESTDHANDLES;
- pi.si.hStdInput = pipe_in[0];
- pi.si.hStdOutput = pipe_out[1];
- pi.si.hStdError = pipe_err[1];
+ pi.si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
+ pi.si.StartupInfo.hStdInput = pipe_in[0];
+ pi.si.StartupInfo.hStdOutput = pipe_out[1];
+ pi.si.StartupInfo.hStdError = pipe_err[1];
- DWORD creation_flags = NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW;
+ SIZE_T attr_list_size = 0;
+ InitializeProcThreadAttributeList(nullptr, 1, 0, &attr_list_size);
+ pi.si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)alloca(attr_list_size);
+ if (!InitializeProcThreadAttributeList(pi.si.lpAttributeList, 1, 0, &attr_list_size)) {
+ CLEAN_PIPES
+ ERR_FAIL_V(ret);
+ }
+ HANDLE handles_to_inherit[] = { pipe_in[0], pipe_out[1], pipe_err[1] };
+ if (!UpdateProcThreadAttribute(
+ pi.si.lpAttributeList,
+ 0,
+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+ handles_to_inherit,
+ sizeof(handles_to_inherit),
+ nullptr,
+ nullptr)) {
+ CLEAN_PIPES
+ DeleteProcThreadAttributeList(pi.si.lpAttributeList);
+ ERR_FAIL_V(ret);
+ }
+
+ DWORD creation_flags = NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT;
Char16String current_dir_name;
size_t str_len = GetCurrentDirectoryW(0, nullptr);
@@ -964,11 +1025,13 @@ Dictionary OS_Windows::execute_with_pipe(const String &p_path, const List<String
if (!CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, true, creation_flags, nullptr, (LPWSTR)current_dir_name.ptr(), si_w, &pi.pi)) {
CLEAN_PIPES
+ DeleteProcThreadAttributeList(pi.si.lpAttributeList);
ERR_FAIL_V_MSG(ret, "Could not create child process: " + command);
}
CloseHandle(pipe_in[0]);
CloseHandle(pipe_out[1]);
CloseHandle(pipe_err[1]);
+ DeleteProcThreadAttributeList(pi.si.lpAttributeList);
ProcessID pid = pi.pi.dwProcessId;
process_map_mutex.lock();
@@ -1000,9 +1063,9 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
ProcessInfo pi;
ZeroMemory(&pi.si, sizeof(pi.si));
- pi.si.cb = sizeof(pi.si);
+ pi.si.StartupInfo.cb = sizeof(pi.si);
ZeroMemory(&pi.pi, sizeof(pi.pi));
- LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si;
+ LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si.StartupInfo;
bool inherit_handles = false;
HANDLE pipe[2] = { nullptr, nullptr };
@@ -1014,16 +1077,40 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
sa.lpSecurityDescriptor = nullptr;
ERR_FAIL_COND_V(!CreatePipe(&pipe[0], &pipe[1], &sa, 0), ERR_CANT_FORK);
- ERR_FAIL_COND_V(!SetHandleInformation(pipe[0], HANDLE_FLAG_INHERIT, 0), ERR_CANT_FORK); // Read handle is for host process only and should not be inherited.
- pi.si.dwFlags |= STARTF_USESTDHANDLES;
- pi.si.hStdOutput = pipe[1];
+ pi.si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
+ pi.si.StartupInfo.hStdOutput = pipe[1];
if (read_stderr) {
- pi.si.hStdError = pipe[1];
+ pi.si.StartupInfo.hStdError = pipe[1];
+ }
+
+ SIZE_T attr_list_size = 0;
+ InitializeProcThreadAttributeList(nullptr, 1, 0, &attr_list_size);
+ pi.si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)alloca(attr_list_size);
+ if (!InitializeProcThreadAttributeList(pi.si.lpAttributeList, 1, 0, &attr_list_size)) {
+ CloseHandle(pipe[0]); // Cleanup pipe handles.
+ CloseHandle(pipe[1]);
+ ERR_FAIL_V(ERR_CANT_FORK);
+ }
+ if (!UpdateProcThreadAttribute(
+ pi.si.lpAttributeList,
+ 0,
+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+ &pipe[1],
+ sizeof(HANDLE),
+ nullptr,
+ nullptr)) {
+ CloseHandle(pipe[0]); // Cleanup pipe handles.
+ CloseHandle(pipe[1]);
+ DeleteProcThreadAttributeList(pi.si.lpAttributeList);
+ ERR_FAIL_V(ERR_CANT_FORK);
}
inherit_handles = true;
}
DWORD creation_flags = NORMAL_PRIORITY_CLASS;
+ if (inherit_handles) {
+ creation_flags |= EXTENDED_STARTUPINFO_PRESENT;
+ }
if (p_open_console) {
creation_flags |= CREATE_NEW_CONSOLE;
} else {
@@ -1046,6 +1133,7 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
if (!ret && r_pipe) {
CloseHandle(pipe[0]); // Cleanup pipe handles.
CloseHandle(pipe[1]);
+ DeleteProcThreadAttributeList(pi.si.lpAttributeList);
}
ERR_FAIL_COND_V_MSG(ret == 0, ERR_CANT_FORK, "Could not create child process: " + command);
@@ -1101,6 +1189,9 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
CloseHandle(pi.pi.hProcess);
CloseHandle(pi.pi.hThread);
+ if (r_pipe) {
+ DeleteProcThreadAttributeList(pi.si.lpAttributeList);
+ }
return OK;
}
@@ -1114,9 +1205,9 @@ Error OS_Windows::create_process(const String &p_path, const List<String> &p_arg
ProcessInfo pi;
ZeroMemory(&pi.si, sizeof(pi.si));
- pi.si.cb = sizeof(pi.si);
+ pi.si.StartupInfo.cb = sizeof(pi.si.StartupInfo);
ZeroMemory(&pi.pi, sizeof(pi.pi));
- LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si;
+ LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si.StartupInfo;
DWORD creation_flags = NORMAL_PRIORITY_CLASS;
if (p_open_console) {
@@ -1437,7 +1528,8 @@ DWRITE_FONT_STRETCH OS_Windows::_stretch_to_dw(int p_stretch) const {
}
Vector<String> OS_Windows::get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale, const String &p_script, int p_weight, int p_stretch, bool p_italic) const {
- if (!dwrite2_init) {
+ // This may be called before TextServerManager has been created, which would cause a crash downstream if we do not check here
+ if (!dwrite2_init || !TextServerManager::get_singleton()) {
return Vector<String>();
}
@@ -1639,16 +1731,115 @@ void OS_Windows::unset_environment(const String &p_var) const {
SetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), nullptr); // Null to delete.
}
-String OS_Windows::get_stdin_string() {
- char buff[1024];
+String OS_Windows::get_stdin_string(int64_t p_buffer_size) {
+ if (get_stdin_type() == STD_HANDLE_INVALID) {
+ return String();
+ }
+
+ Vector<uint8_t> data;
+ data.resize(p_buffer_size);
DWORD count = 0;
- if (ReadFile(GetStdHandle(STD_INPUT_HANDLE), buff, 1024, &count, nullptr)) {
- return String::utf8((const char *)buff, count);
+ if (ReadFile(GetStdHandle(STD_INPUT_HANDLE), data.ptrw(), data.size(), &count, nullptr)) {
+ return String::utf8((const char *)data.ptr(), count).replace("\r\n", "\n").rstrip("\n");
}
return String();
}
+PackedByteArray OS_Windows::get_stdin_buffer(int64_t p_buffer_size) {
+ Vector<uint8_t> data;
+ data.resize(p_buffer_size);
+ DWORD count = 0;
+ if (ReadFile(GetStdHandle(STD_INPUT_HANDLE), data.ptrw(), data.size(), &count, nullptr)) {
+ return data;
+ }
+
+ return PackedByteArray();
+}
+
+OS_Windows::StdHandleType OS_Windows::get_stdin_type() const {
+ HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
+ if (h == 0 || h == INVALID_HANDLE_VALUE) {
+ return STD_HANDLE_INVALID;
+ }
+ DWORD ftype = GetFileType(h);
+ if (ftype == FILE_TYPE_UNKNOWN && GetLastError() != ERROR_SUCCESS) {
+ return STD_HANDLE_UNKNOWN;
+ }
+ ftype &= ~(FILE_TYPE_REMOTE);
+
+ if (ftype == FILE_TYPE_DISK) {
+ return STD_HANDLE_FILE;
+ } else if (ftype == FILE_TYPE_PIPE) {
+ return STD_HANDLE_PIPE;
+ } else {
+ DWORD conmode = 0;
+ BOOL res = GetConsoleMode(h, &conmode);
+ if (!res && (GetLastError() == ERROR_INVALID_HANDLE)) {
+ return STD_HANDLE_UNKNOWN; // Unknown character device.
+ } else {
+#ifndef WINDOWS_SUBSYSTEM_CONSOLE
+ if (!is_using_con_wrapper()) {
+ return STD_HANDLE_INVALID; // Window app can't read stdin input without werapper.
+ }
+#endif
+ return STD_HANDLE_CONSOLE;
+ }
+ }
+}
+
+OS_Windows::StdHandleType OS_Windows::get_stdout_type() const {
+ HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (h == 0 || h == INVALID_HANDLE_VALUE) {
+ return STD_HANDLE_INVALID;
+ }
+ DWORD ftype = GetFileType(h);
+ if (ftype == FILE_TYPE_UNKNOWN && GetLastError() != ERROR_SUCCESS) {
+ return STD_HANDLE_UNKNOWN;
+ }
+ ftype &= ~(FILE_TYPE_REMOTE);
+
+ if (ftype == FILE_TYPE_DISK) {
+ return STD_HANDLE_FILE;
+ } else if (ftype == FILE_TYPE_PIPE) {
+ return STD_HANDLE_PIPE;
+ } else {
+ DWORD conmode = 0;
+ BOOL res = GetConsoleMode(h, &conmode);
+ if (!res && (GetLastError() == ERROR_INVALID_HANDLE)) {
+ return STD_HANDLE_UNKNOWN; // Unknown character device.
+ } else {
+ return STD_HANDLE_CONSOLE;
+ }
+ }
+}
+
+OS_Windows::StdHandleType OS_Windows::get_stderr_type() const {
+ HANDLE h = GetStdHandle(STD_ERROR_HANDLE);
+ if (h == 0 || h == INVALID_HANDLE_VALUE) {
+ return STD_HANDLE_INVALID;
+ }
+ DWORD ftype = GetFileType(h);
+ if (ftype == FILE_TYPE_UNKNOWN && GetLastError() != ERROR_SUCCESS) {
+ return STD_HANDLE_UNKNOWN;
+ }
+ ftype &= ~(FILE_TYPE_REMOTE);
+
+ if (ftype == FILE_TYPE_DISK) {
+ return STD_HANDLE_FILE;
+ } else if (ftype == FILE_TYPE_PIPE) {
+ return STD_HANDLE_PIPE;
+ } else {
+ DWORD conmode = 0;
+ BOOL res = GetConsoleMode(h, &conmode);
+ if (!res && (GetLastError() == ERROR_INVALID_HANDLE)) {
+ return STD_HANDLE_UNKNOWN; // Unknown character device.
+ } else {
+ return STD_HANDLE_CONSOLE;
+ }
+ }
+}
+
Error OS_Windows::shell_open(const String &p_uri) {
INT_PTR ret = (INT_PTR)ShellExecuteW(nullptr, nullptr, (LPCWSTR)(p_uri.utf16().get_data()), nullptr, nullptr, SW_SHOWNORMAL);
if (ret > 32) {
@@ -1740,6 +1931,34 @@ String OS_Windows::get_locale() const {
return "en";
}
+String OS_Windows::get_model_name() const {
+ HKEY hkey;
+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Hardware\\Description\\System\\BIOS", 0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS) {
+ return OS::get_model_name();
+ }
+
+ String sys_name;
+ String board_name;
+ WCHAR buffer[256];
+ DWORD buffer_len = 256;
+ DWORD vtype = REG_SZ;
+ if (RegQueryValueExW(hkey, L"SystemProductName", nullptr, &vtype, (LPBYTE)buffer, &buffer_len) == ERROR_SUCCESS && buffer_len != 0) {
+ sys_name = String::utf16((const char16_t *)buffer, buffer_len).strip_edges();
+ }
+ buffer_len = 256;
+ if (RegQueryValueExW(hkey, L"BaseBoardProduct", nullptr, &vtype, (LPBYTE)buffer, &buffer_len) == ERROR_SUCCESS && buffer_len != 0) {
+ board_name = String::utf16((const char16_t *)buffer, buffer_len).strip_edges();
+ }
+ RegCloseKey(hkey);
+ if (!sys_name.is_empty() && sys_name.to_lower() != "system product name") {
+ return sys_name;
+ }
+ if (!board_name.is_empty() && board_name.to_lower() != "base board product") {
+ return board_name;
+ }
+ return OS::get_model_name();
+}
+
String OS_Windows::get_processor_name() const {
const String id = "Hardware\\Description\\System\\CentralProcessor\\0";
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 4f9bc049ee..fd98f9b14b 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -37,7 +37,6 @@
#include "core/config/project_settings.h"
#include "core/input/input.h"
#include "core/os/os.h"
-#include "drivers/unix/ip_unix.h"
#include "drivers/wasapi/audio_driver_wasapi.h"
#include "drivers/winmidi/midi_driver_winmidi.h"
#include "servers/audio_server.h"
@@ -134,6 +133,8 @@ class OS_Windows : public OS {
DWRITE_FONT_WEIGHT _weight_to_dw(int p_weight) const;
DWRITE_FONT_STRETCH _stretch_to_dw(int p_stretch) const;
+ bool is_using_con_wrapper() const;
+
// functions used by main to initialize/deinitialize the OS
protected:
virtual void initialize() override;
@@ -143,12 +144,17 @@ protected:
virtual void finalize() override;
virtual void finalize_core() override;
- virtual String get_stdin_string() override;
+
+ virtual String get_stdin_string(int64_t p_buffer_size = 1024) override;
+ virtual PackedByteArray get_stdin_buffer(int64_t p_buffer_size = 1024) override;
+ virtual StdHandleType get_stdin_type() const override;
+ virtual StdHandleType get_stdout_type() const override;
+ virtual StdHandleType get_stderr_type() const override;
String _quote_command_line_argument(const String &p_text) const;
struct ProcessInfo {
- STARTUPINFO si;
+ STARTUPINFOEX si;
PROCESS_INFORMATION pi;
mutable bool is_running = true;
mutable int exit_code = -1;
@@ -210,6 +216,8 @@ public:
virtual String get_processor_name() const override;
+ virtual String get_model_name() const override;
+
virtual uint64_t get_embedded_pck_offset() const override;
virtual String get_config_path() const override;
diff --git a/platform/windows/tts_windows.cpp b/platform/windows/tts_windows.cpp
index 39a8f3e120..e9ef50d736 100644
--- a/platform/windows/tts_windows.cpp
+++ b/platform/windows/tts_windows.cpp
@@ -43,7 +43,7 @@ void __stdcall TTS_Windows::speech_event_callback(WPARAM wParam, LPARAM lParam)
} else if (event.eEventId == SPEI_END_INPUT_STREAM) {
DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_ENDED, tts->ids[stream_num].id);
tts->ids.erase(stream_num);
- tts->_update_tts();
+ tts->update_requested = true;
} else if (event.eEventId == SPEI_WORD_BOUNDARY) {
const Char16String &string = tts->ids[stream_num].string;
int pos = 0;
@@ -60,8 +60,8 @@ void __stdcall TTS_Windows::speech_event_callback(WPARAM wParam, LPARAM lParam)
}
}
-void TTS_Windows::_update_tts() {
- if (!is_speaking() && !paused && queue.size() > 0) {
+void TTS_Windows::process_events() {
+ if (update_requested && !paused && queue.size() > 0 && !is_speaking()) {
DisplayServer::TTSUtterance &message = queue.front()->get();
String text;
@@ -110,6 +110,8 @@ void TTS_Windows::_update_tts() {
ids[(uint32_t)stream_number] = ut;
queue.pop_front();
+
+ update_requested = false;
}
}
@@ -207,7 +209,7 @@ void TTS_Windows::speak(const String &p_text, const String &p_voice, int p_volum
if (is_paused()) {
resume();
} else {
- _update_tts();
+ update_requested = true;
}
}
diff --git a/platform/windows/tts_windows.h b/platform/windows/tts_windows.h
index 33b597c612..657cb608d6 100644
--- a/platform/windows/tts_windows.h
+++ b/platform/windows/tts_windows.h
@@ -55,9 +55,9 @@ class TTS_Windows {
int id;
};
HashMap<uint32_t, UTData> ids;
+ bool update_requested = false;
static void __stdcall speech_event_callback(WPARAM wParam, LPARAM lParam);
- void _update_tts();
static TTS_Windows *singleton;
@@ -73,6 +73,8 @@ public:
void resume();
void stop();
+ void process_events();
+
TTS_Windows();
~TTS_Windows();
};
diff --git a/platform/windows/windows_terminal_logger.cpp b/platform/windows/windows_terminal_logger.cpp
index 6c54faa13a..e25c612008 100644
--- a/platform/windows/windows_terminal_logger.cpp
+++ b/platform/windows/windows_terminal_logger.cpp
@@ -30,6 +30,8 @@
#include "windows_terminal_logger.h"
+#include "core/os/os.h"
+
#ifdef WINDOWS_ENABLED
#include <stdio.h>
@@ -78,7 +80,7 @@ void WindowsTerminalLogger::log_error(const char *p_function, const char *p_file
}
HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE);
- if (!hCon || hCon == INVALID_HANDLE_VALUE) {
+ if (OS::get_singleton()->get_stdout_type() != OS::STD_HANDLE_CONSOLE || !hCon || hCon == INVALID_HANDLE_VALUE) {
StdLogger::log_error(p_function, p_file, p_line, p_code, p_rationale, p_type);
} else {
CONSOLE_SCREEN_BUFFER_INFO sbi; //original
diff --git a/platform_methods.py b/platform_methods.py
index 2c4eb0d1dd..201df3c0b5 100644
--- a/platform_methods.py
+++ b/platform_methods.py
@@ -8,6 +8,13 @@ import methods
# NOTE: The multiprocessing module is not compatible with SCons due to conflict on cPickle
+compatibility_platform_aliases = {
+ "osx": "macos",
+ "iphone": "ios",
+ "x11": "linuxbsd",
+ "javascript": "web",
+}
+
# CPU architecture options.
architectures = ["x86_32", "x86_64", "arm32", "arm64", "rv64", "ppc32", "ppc64", "wasm32"]
architecture_aliases = {
diff --git a/pyproject.toml b/pyproject.toml
index a4bfd27816..403d9fd675 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,14 +1,14 @@
[tool.mypy]
-ignore_missing_imports = true
disallow_any_generics = true
+explicit_package_bases = true
+ignore_missing_imports = true
+namespace_packages = true
no_implicit_optional = true
pretty = true
show_column_numbers = true
warn_redundant_casts = true
warn_return_any = true
warn_unreachable = true
-namespace_packages = true
-explicit_package_bases = true
exclude = ["thirdparty/"]
python_version = "3.8"
@@ -16,7 +16,7 @@ python_version = "3.8"
extend-exclude = ["thirdparty"]
extend-include = ["SConstruct", "SCsub"]
line-length = 120
-target-version = "py37"
+target-version = "py38"
[tool.ruff.lint]
extend-select = [
@@ -42,50 +42,50 @@ section-order = [
]
[tool.codespell]
-enable-colors = ""
-write-changes = ""
-check-hidden = ""
+enable-colors = true
+write-changes = true
+check-hidden = true
quiet-level = 3
-builtin = "clear,rare,en-GB_to_en-US"
-skip = """\
- .mailmap,
- *.desktop,
- *.gitignore,
- *.po,
- *.pot,
- *.rc,
- AUTHORS.md,
- COPYRIGHT.txt,
- core/input/gamecontrollerdb.txt,
- core/string/locales.h,
- DONORS.md,
- editor/project_converter_3_to_4.cpp,
- platform/android/java/lib/src/com/*,
- platform/web/package-lock.json
-"""
-ignore-words-list = """\
- breaked,
- cancelled,
- checkin,
- colour,
- curvelinear,
- doubleclick,
- expct,
- findn,
- gird,
- hel,
- inout,
- labelin,
- lod,
- mis,
- nd,
- numer,
- ot,
- outin,
- parm,
- requestor,
- te,
- textin,
- thirdparty,
- vai
-"""
+builtin = ["clear", "rare", "en-GB_to_en-US"]
+skip = [
+ ".mailmap",
+ "*.desktop",
+ "*.gitignore",
+ "*.po",
+ "*.pot",
+ "*.rc",
+ "AUTHORS.md",
+ "COPYRIGHT.txt",
+ "core/input/gamecontrollerdb.txt",
+ "core/string/locales.h",
+ "DONORS.md",
+ "editor/project_converter_3_to_4.cpp",
+ "platform/android/java/lib/src/com/*",
+ "platform/web/package-lock.json",
+]
+ignore-words-list = [
+ "breaked",
+ "cancelled",
+ "checkin",
+ "colour",
+ "curvelinear",
+ "doubleclick",
+ "expct",
+ "findn",
+ "gird",
+ "hel",
+ "inout",
+ "labelin",
+ "lod",
+ "mis",
+ "nd",
+ "numer",
+ "ot",
+ "outin",
+ "parm",
+ "requestor",
+ "te",
+ "textin",
+ "thirdparty",
+ "vai",
+]
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index 7c60e47e64..8aaa230075 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -410,7 +410,7 @@ void AudioStreamPlayer2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume_db", PROPERTY_HINT_RANGE, "-80,24,suffix:dB"), "set_volume_db", "get_volume_db");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,4,0.01,or_greater"), "set_pitch_scale", "get_pitch_scale");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_playing", "is_playing");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_ONESHOT, "", PROPERTY_USAGE_EDITOR), "set_playing", "is_playing");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "1,4096,1,or_greater,exp,suffix:px"), "set_max_distance", "get_max_distance");
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index 754afb0527..5c1524b211 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -506,6 +506,10 @@ bool CPUParticles2D::get_split_scale() {
}
void CPUParticles2D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "emitting") {
+ p_property.hint = one_shot ? PROPERTY_HINT_ONESHOT : PROPERTY_HINT_NONE;
+ }
+
if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) {
p_property.usage = PROPERTY_USAGE_NONE;
}
@@ -1285,7 +1289,7 @@ void CPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("restart"), &CPUParticles2D::restart);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting", PROPERTY_HINT_ONESHOT), "set_emitting", "is_emitting");
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount");
ADD_GROUP("Time", "");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater,exp,suffix:s"), "set_lifetime", "get_lifetime");
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index b50881cb89..8dac13c38b 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -384,6 +384,9 @@ Ref<Texture2D> GPUParticles2D::get_texture() const {
}
void GPUParticles2D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "emitting") {
+ p_property.hint = one_shot ? PROPERTY_HINT_ONESHOT : PROPERTY_HINT_NONE;
+ }
}
void GPUParticles2D::emit_particle(const Transform2D &p_transform2d, const Vector2 &p_velocity2d, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
@@ -818,7 +821,7 @@ void GPUParticles2D::_bind_methods() {
ADD_SIGNAL(MethodInfo("finished"));
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting", PROPERTY_HINT_ONESHOT), "set_emitting", "is_emitting");
ADD_PROPERTY_DEFAULT("emitting", true); // Workaround for doctool in headless mode, as dummy rasterizer always returns false.
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "amount_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001"), "set_amount_ratio", "get_amount_ratio");
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index 21648bbc49..0b54d1e604 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -418,7 +418,7 @@ Vector2 PointLight2D::get_texture_offset() const {
}
PackedStringArray PointLight2D::get_configuration_warnings() const {
- PackedStringArray warnings = Node2D::get_configuration_warnings();
+ PackedStringArray warnings = Light2D::get_configuration_warnings();
if (!texture.is_valid()) {
warnings.push_back(RTR("A texture with the shape of the light must be supplied to the \"Texture\" property."));
diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp
index f6502a77e9..46bcda9c6d 100644
--- a/scene/2d/navigation_obstacle_2d.cpp
+++ b/scene/2d/navigation_obstacle_2d.cpp
@@ -89,7 +89,7 @@ void NavigationObstacle2D::_notification(int p_what) {
previous_transform = get_global_transform();
// need to trigger map controlled agent assignment somehow for the fake_agent since obstacles use no callback like regular agents
NavigationServer2D::get_singleton()->obstacle_set_avoidance_enabled(obstacle, avoidance_enabled);
- _update_position(get_global_position());
+ _update_transform();
set_physics_process_internal(true);
#ifdef DEBUG_ENABLED
RS::get_singleton()->canvas_item_set_parent(debug_canvas_item, get_world_2d()->get_canvas());
@@ -142,7 +142,7 @@ void NavigationObstacle2D::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (is_inside_tree()) {
- _update_position(get_global_position());
+ _update_transform();
if (velocity_submitted) {
velocity_submitted = false;
@@ -167,8 +167,7 @@ void NavigationObstacle2D::_notification(int p_what) {
if (is_debug_enabled) {
RS::get_singleton()->canvas_item_clear(debug_canvas_item);
- Transform2D debug_transform = Transform2D(0.0, get_global_position());
- RS::get_singleton()->canvas_item_set_transform(debug_canvas_item, debug_transform);
+ RS::get_singleton()->canvas_item_set_transform(debug_canvas_item, Transform2D());
_update_fake_agent_radius_debug();
_update_static_obstacle_debug();
}
@@ -207,7 +206,8 @@ NavigationObstacle2D::~NavigationObstacle2D() {
void NavigationObstacle2D::set_vertices(const Vector<Vector2> &p_vertices) {
vertices = p_vertices;
- NavigationServer2D::get_singleton()->obstacle_set_vertices(obstacle, vertices);
+ const Transform2D node_transform = is_inside_tree() ? get_global_transform() : Transform2D();
+ NavigationServer2D::get_singleton()->obstacle_set_vertices(obstacle, node_transform.xform(vertices));
#ifdef DEBUG_ENABLED
queue_redraw();
#endif // DEBUG_ENABLED
@@ -238,7 +238,8 @@ void NavigationObstacle2D::set_radius(real_t p_radius) {
radius = p_radius;
- NavigationServer2D::get_singleton()->obstacle_set_radius(obstacle, radius);
+ const Vector2 safe_scale = (is_inside_tree() ? get_global_scale() : get_scale()).abs().maxf(0.001);
+ NavigationServer2D::get_singleton()->obstacle_set_radius(obstacle, safe_scale[safe_scale.max_axis_index()] * radius);
#ifdef DEBUG_ENABLED
queue_redraw();
#endif // DEBUG_ENABLED
@@ -311,6 +312,25 @@ bool NavigationObstacle2D::get_carve_navigation_mesh() const {
return carve_navigation_mesh;
}
+PackedStringArray NavigationObstacle2D::get_configuration_warnings() const {
+ PackedStringArray warnings = Node2D::get_configuration_warnings();
+
+ const Vector2 global_scale = get_global_scale();
+ if (global_scale.x < 0.001 || global_scale.y < 0.001) {
+ warnings.push_back(RTR("NavigationObstacle2D does not support negative or zero scaling."));
+ }
+
+ if (radius > 0.0 && !get_global_transform().is_conformal()) {
+ warnings.push_back(RTR("The agent radius can only be scaled uniformly. The largest value along the two axes of the global scale will be used to scale the radius. This value may change in unexpected ways when the node is rotated."));
+ }
+
+ if (radius > 0.0 && get_global_skew() != 0.0) {
+ warnings.push_back(RTR("Skew has no effect on the agent radius."));
+ }
+
+ return warnings;
+}
+
void NavigationObstacle2D::_update_map(RID p_map) {
map_current = p_map;
NavigationServer2D::get_singleton()->obstacle_set_map(obstacle, p_map);
@@ -323,12 +343,27 @@ void NavigationObstacle2D::_update_position(const Vector2 p_position) {
#endif // DEBUG_ENABLED
}
+void NavigationObstacle2D::_update_transform() {
+ _update_position(get_global_position());
+ // Prevent non-positive or non-uniform scaling of dynamic obstacle radius.
+ const Vector2 safe_scale = get_global_scale().abs().maxf(0.001);
+ const float scaling_max_value = safe_scale[safe_scale.max_axis_index()];
+ NavigationServer2D::get_singleton()->obstacle_set_radius(obstacle, scaling_max_value * radius);
+ NavigationServer2D::get_singleton()->obstacle_set_vertices(obstacle, get_global_transform().translated(-get_global_position()).xform(vertices));
+#ifdef DEBUG_ENABLED
+ queue_redraw();
+#endif // DEBUG_ENABLED
+}
+
#ifdef DEBUG_ENABLED
void NavigationObstacle2D::_update_fake_agent_radius_debug() {
if (radius > 0.0 && NavigationServer2D::get_singleton()->get_debug_navigation_avoidance_enable_obstacles_radius()) {
Color debug_radius_color = NavigationServer2D::get_singleton()->get_debug_navigation_avoidance_obstacles_radius_color();
-
- RS::get_singleton()->canvas_item_add_circle(debug_canvas_item, Vector2(), radius, debug_radius_color);
+ // Prevent non-positive scaling.
+ const Vector2 safe_scale = get_global_scale().abs().maxf(0.001);
+ // Agent radius is a scalar value and does not support non-uniform scaling, choose the largest axis.
+ const float scaling_max_value = safe_scale[safe_scale.max_axis_index()];
+ RS::get_singleton()->canvas_item_add_circle(debug_canvas_item, get_global_position(), scaling_max_value * radius, debug_radius_color);
}
}
#endif // DEBUG_ENABLED
@@ -352,7 +387,7 @@ void NavigationObstacle2D::_update_static_obstacle_debug() {
debug_obstacle_polygon_colors.resize(debug_obstacle_polygon_vertices.size());
debug_obstacle_polygon_colors.fill(debug_static_obstacle_face_color);
- RS::get_singleton()->canvas_item_add_polygon(debug_canvas_item, debug_obstacle_polygon_vertices, debug_obstacle_polygon_colors);
+ RS::get_singleton()->canvas_item_add_polygon(debug_canvas_item, get_global_transform().xform(debug_obstacle_polygon_vertices), debug_obstacle_polygon_colors);
Color debug_static_obstacle_edge_color;
@@ -370,7 +405,8 @@ void NavigationObstacle2D::_update_static_obstacle_debug() {
debug_obstacle_line_colors.resize(debug_obstacle_line_vertices.size());
debug_obstacle_line_colors.fill(debug_static_obstacle_edge_color);
- RS::get_singleton()->canvas_item_add_polyline(debug_canvas_item, debug_obstacle_line_vertices, debug_obstacle_line_colors, 4.0);
+ // Transforming the vertices directly instead of the canvas item in order to not affect the circle shape by non-uniform scales.
+ RS::get_singleton()->canvas_item_add_polyline(debug_canvas_item, get_global_transform().xform(debug_obstacle_line_vertices), debug_obstacle_line_colors, 4.0);
}
}
#endif // DEBUG_ENABLED
diff --git a/scene/2d/navigation_obstacle_2d.h b/scene/2d/navigation_obstacle_2d.h
index 28c5f902e6..6e3596acf4 100644
--- a/scene/2d/navigation_obstacle_2d.h
+++ b/scene/2d/navigation_obstacle_2d.h
@@ -106,9 +106,12 @@ public:
void set_carve_navigation_mesh(bool p_enabled);
bool get_carve_navigation_mesh() const;
+ PackedStringArray get_configuration_warnings() const override;
+
private:
void _update_map(RID p_map);
void _update_position(const Vector2 p_position);
+ void _update_transform();
};
#endif // NAVIGATION_OBSTACLE_2D_H
diff --git a/scene/2d/physics/rigid_body_2d.cpp b/scene/2d/physics/rigid_body_2d.cpp
index 402e5c8b95..4b1cde6b7a 100644
--- a/scene/2d/physics/rigid_body_2d.cpp
+++ b/scene/2d/physics/rigid_body_2d.cpp
@@ -641,7 +641,7 @@ void RigidBody2D::_notification(int p_what) {
PackedStringArray RigidBody2D::get_configuration_warnings() const {
Transform2D t = get_transform();
- PackedStringArray warnings = CollisionObject2D::get_configuration_warnings();
+ PackedStringArray warnings = PhysicsBody2D::get_configuration_warnings();
if (ABS(t.columns[0].length() - 1.0) > 0.05 || ABS(t.columns[1].length() - 1.0) > 0.05) {
warnings.push_back(RTR("Size changes to RigidBody2D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 20cbbc091a..8e9500cdbe 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -75,7 +75,7 @@ void TileMap::_set_tile_map_data_using_compatibility_format(int p_layer, TileMap
for (int i = 0; i < c; i += offset) {
const uint8_t *ptr = (const uint8_t *)&r[i];
uint8_t local[12];
- const int buffer_size = (format == TILE_MAP_DATA_FORMAT_2) ? 12 : 8;
+ const int buffer_size = (p_format >= TILE_MAP_DATA_FORMAT_2) ? 12 : 8;
for (int j = 0; j < buffer_size; j++) {
local[j] = ptr[j];
}
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 98bee2115c..eb75650399 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -834,7 +834,7 @@ void AudioStreamPlayer3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_size", PROPERTY_HINT_RANGE, "0.1,100,0.01,or_greater"), "set_unit_size", "get_unit_size");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_db", PROPERTY_HINT_RANGE, "-24,6,suffix:dB"), "set_max_db", "get_max_db");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,4,0.01,or_greater"), "set_pitch_scale", "get_pitch_scale");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_playing", "is_playing");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_ONESHOT, "", PROPERTY_USAGE_EDITOR), "set_playing", "is_playing");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,or_greater,suffix:m"), "set_max_distance", "get_max_distance");
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index 5b84bf903f..4424032653 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -543,6 +543,10 @@ AABB CPUParticles3D::capture_aabb() const {
}
void CPUParticles3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "emitting") {
+ p_property.hint = one_shot ? PROPERTY_HINT_ONESHOT : PROPERTY_HINT_NONE;
+ }
+
if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) {
p_property.usage = PROPERTY_USAGE_NONE;
}
@@ -1481,7 +1485,7 @@ void CPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("restart"), &CPUParticles3D::restart);
ClassDB::bind_method(D_METHOD("capture_aabb"), &CPUParticles3D::capture_aabb);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting", PROPERTY_HINT_ONESHOT), "set_emitting", "is_emitting");
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount");
ADD_GROUP("Time", "");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater,exp,suffix:s"), "set_lifetime", "get_lifetime");
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index b48a3a87c7..760409d9a0 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -414,6 +414,10 @@ AABB GPUParticles3D::capture_aabb() const {
}
void GPUParticles3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "emitting") {
+ p_property.hint = one_shot ? PROPERTY_HINT_ONESHOT : PROPERTY_HINT_NONE;
+ }
+
if (p_property.name.begins_with("draw_pass_")) {
int index = p_property.name.get_slicec('_', 2).to_int() - 1;
if (index >= draw_passes.size()) {
@@ -744,7 +748,7 @@ void GPUParticles3D::_bind_methods() {
ADD_SIGNAL(MethodInfo("finished"));
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting", PROPERTY_HINT_ONESHOT), "set_emitting", "is_emitting");
ADD_PROPERTY_DEFAULT("emitting", true); // Workaround for doctool in headless mode, as dummy rasterizer always returns false.
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "amount_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001"), "set_amount_ratio", "get_amount_ratio");
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index c658bfd799..aa4445a7ba 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -333,9 +333,7 @@ void LightmapGI::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound> &m
mf.node_path = get_path_to(mi);
mf.subindex = -1;
mf.mesh = mesh;
-
- static const int lightmap_scale[GeometryInstance3D::LIGHTMAP_SCALE_MAX] = { 1, 2, 4, 8 };
- mf.lightmap_scale = lightmap_scale[mi->get_lightmap_scale()];
+ mf.lightmap_scale = mi->get_lightmap_texel_scale();
Ref<Material> all_override = mi->get_material_override();
for (int i = 0; i < mesh->get_surface_count(); i++) {
@@ -369,7 +367,7 @@ void LightmapGI::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound> &m
mf.xform = xf * mesh_xf;
mf.node_path = get_path_to(s);
mf.subindex = i / 2;
- mf.lightmap_scale = 1;
+ mf.lightmap_scale = 1.0;
mf.mesh = mesh;
meshes.push_back(mf);
@@ -1191,6 +1189,8 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
return BAKE_ERROR_MESHES_INVALID;
} else if (bake_err == Lightmapper::BAKE_ERROR_ATLAS_TOO_SMALL) {
return BAKE_ERROR_ATLAS_TOO_SMALL;
+ } else if (bake_err == Lightmapper::BAKE_ERROR_USER_ABORTED) {
+ return BAKE_ERROR_USER_ABORTED;
}
// POSTBAKE: Save Textures.
diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h
index 0476061c60..faa8b84fa1 100644
--- a/scene/3d/lightmap_gi.h
+++ b/scene/3d/lightmap_gi.h
@@ -194,7 +194,7 @@ private:
NodePath node_path;
int32_t subindex = 0;
Ref<Mesh> mesh;
- int32_t lightmap_scale = 0;
+ float lightmap_scale = 0.0;
Vector<Ref<Material>> overrides;
};
diff --git a/scene/3d/lightmapper.h b/scene/3d/lightmapper.h
index 9aa8ef8ccb..1228c63edc 100644
--- a/scene/3d/lightmapper.h
+++ b/scene/3d/lightmapper.h
@@ -147,6 +147,7 @@ public:
BAKE_ERROR_TEXTURE_EXCEEDS_MAX_SIZE,
BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES,
BAKE_ERROR_ATLAS_TOO_SMALL,
+ BAKE_ERROR_USER_ABORTED,
};
enum BakeQuality {
diff --git a/scene/3d/look_at_modifier_3d.cpp b/scene/3d/look_at_modifier_3d.cpp
new file mode 100644
index 0000000000..04dae61dce
--- /dev/null
+++ b/scene/3d/look_at_modifier_3d.cpp
@@ -0,0 +1,835 @@
+/**************************************************************************/
+/* look_at_modifier_3d.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "look_at_modifier_3d.h"
+
+void LookAtModifier3D::_validate_property(PropertyInfo &p_property) const {
+ SkeletonModifier3D::_validate_property(p_property);
+
+ if (p_property.name == "bone_name" || p_property.name == "origin_bone_name") {
+ Skeleton3D *skeleton = get_skeleton();
+ if (skeleton) {
+ p_property.hint = PROPERTY_HINT_ENUM;
+ p_property.hint_string = skeleton->get_concatenated_bone_names();
+ } else {
+ p_property.hint = PROPERTY_HINT_NONE;
+ p_property.hint_string = "";
+ }
+ }
+
+ if (origin_from == ORIGIN_FROM_SPECIFIC_BONE) {
+ if (p_property.name == "origin_external_node") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+ } else if (origin_from == ORIGIN_FROM_EXTERNAL_NODE) {
+ if (p_property.name == "origin_bone" || p_property.name == "origin_bone_name") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+ } else {
+ if (p_property.name == "origin_external_node" || p_property.name == "origin_bone" || p_property.name == "origin_bone_name") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+ }
+
+ if ((!use_angle_limitation &&
+ (p_property.name == "symmetry_limitation" || p_property.name.ends_with("limit_angle") || p_property.name.ends_with("damp_threshold"))) ||
+ (!use_secondary_rotation && p_property.name.begins_with("secondary_")) ||
+ (!symmetry_limitation && (p_property.name == "primary_limit_angle" || p_property.name == "primary_damp_threshold" || p_property.name == "secondary_limit_angle" || p_property.name == "secondary_damp_threshold")) ||
+ (symmetry_limitation && (p_property.name.begins_with("primary_positive") || p_property.name.begins_with("primary_negative") || p_property.name.begins_with("secondary_positive") || (p_property.name.begins_with("secondary_negative"))))) {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+}
+
+PackedStringArray LookAtModifier3D::get_configuration_warnings() const {
+ PackedStringArray warnings = SkeletonModifier3D::get_configuration_warnings();
+ if (get_axis_from_bone_axis(forward_axis) == primary_rotation_axis) {
+ warnings.push_back(RTR("Forward axis and primary rotation axis must not be parallel."));
+ }
+ return warnings;
+}
+
+void LookAtModifier3D::set_bone_name(const String &p_bone_name) {
+ bone_name = p_bone_name;
+ Skeleton3D *sk = get_skeleton();
+ if (sk) {
+ set_bone(sk->find_bone(bone_name));
+ }
+}
+
+String LookAtModifier3D::get_bone_name() const {
+ return bone_name;
+}
+
+void LookAtModifier3D::set_bone(int p_bone) {
+ bone = p_bone;
+ Skeleton3D *sk = get_skeleton();
+ if (sk) {
+ if (bone <= -1 || bone >= sk->get_bone_count()) {
+ WARN_PRINT("Bone index out of range!");
+ bone = -1;
+ } else {
+ bone_name = sk->get_bone_name(bone);
+ }
+ }
+}
+
+int LookAtModifier3D::get_bone() const {
+ return bone;
+}
+
+void LookAtModifier3D::set_forward_axis(BoneAxis p_axis) {
+ forward_axis = p_axis;
+ update_configuration_warnings();
+}
+
+LookAtModifier3D::BoneAxis LookAtModifier3D::get_forward_axis() const {
+ return forward_axis;
+}
+
+void LookAtModifier3D::set_primary_rotation_axis(Vector3::Axis p_axis) {
+ primary_rotation_axis = p_axis;
+ update_configuration_warnings();
+}
+
+Vector3::Axis LookAtModifier3D::get_primary_rotation_axis() const {
+ return primary_rotation_axis;
+}
+
+void LookAtModifier3D::set_use_secondary_rotation(bool p_enabled) {
+ use_secondary_rotation = p_enabled;
+ notify_property_list_changed();
+}
+
+bool LookAtModifier3D::is_using_secondary_rotation() const {
+ return use_secondary_rotation;
+}
+
+void LookAtModifier3D::set_target_node(const NodePath &p_target_node) {
+ if (target_node != p_target_node) {
+ init_transition();
+ }
+ target_node = p_target_node;
+}
+
+NodePath LookAtModifier3D::get_target_node() const {
+ return target_node;
+}
+
+// For origin settings.
+
+void LookAtModifier3D::set_origin_from(OriginFrom p_origin_from) {
+ origin_from = p_origin_from;
+ notify_property_list_changed();
+}
+
+LookAtModifier3D::OriginFrom LookAtModifier3D::get_origin_from() const {
+ return origin_from;
+}
+
+void LookAtModifier3D::set_origin_bone_name(const String &p_bone_name) {
+ origin_bone_name = p_bone_name;
+ Skeleton3D *sk = get_skeleton();
+ if (sk) {
+ set_origin_bone(sk->find_bone(origin_bone_name));
+ }
+}
+
+String LookAtModifier3D::get_origin_bone_name() const {
+ return origin_bone_name;
+}
+
+void LookAtModifier3D::set_origin_bone(int p_bone) {
+ origin_bone = p_bone;
+ Skeleton3D *sk = get_skeleton();
+ if (sk) {
+ if (origin_bone <= -1 || origin_bone >= sk->get_bone_count()) {
+ WARN_PRINT("Bone index out of range!");
+ origin_bone = -1;
+ } else {
+ origin_bone_name = sk->get_bone_name(origin_bone);
+ }
+ }
+}
+
+int LookAtModifier3D::get_origin_bone() const {
+ return origin_bone;
+}
+
+void LookAtModifier3D::set_origin_external_node(const NodePath &p_external_node) {
+ origin_external_node = p_external_node;
+}
+
+NodePath LookAtModifier3D::get_origin_external_node() const {
+ return origin_external_node;
+}
+
+void LookAtModifier3D::set_origin_offset(const Vector3 &p_offset) {
+ origin_offset = p_offset;
+}
+
+Vector3 LookAtModifier3D::get_origin_offset() const {
+ return origin_offset;
+}
+
+void LookAtModifier3D::set_origin_safe_margin(float p_margin) {
+ origin_safe_margin = p_margin;
+}
+
+float LookAtModifier3D::get_origin_safe_margin() const {
+ return origin_safe_margin;
+}
+
+// For time-based interpolation.
+
+void LookAtModifier3D::set_duration(float p_duration) {
+ duration = p_duration;
+ if (Math::is_zero_approx(p_duration)) {
+ time_step = 0;
+ remaining = 0;
+ } else {
+ time_step = 1.0 / p_duration; // Cache to avoid division.
+ }
+}
+
+float LookAtModifier3D::get_duration() const {
+ return duration;
+}
+
+void LookAtModifier3D::set_transition_type(Tween::TransitionType p_transition_type) {
+ transition_type = p_transition_type;
+}
+
+Tween::TransitionType LookAtModifier3D::get_transition_type() const {
+ return transition_type;
+}
+
+void LookAtModifier3D::set_ease_type(Tween::EaseType p_ease_type) {
+ ease_type = p_ease_type;
+}
+
+Tween::EaseType LookAtModifier3D::get_ease_type() const {
+ return ease_type;
+}
+
+// For angle limitation.
+
+void LookAtModifier3D::set_use_angle_limitation(bool p_enabled) {
+ use_angle_limitation = p_enabled;
+ notify_property_list_changed();
+}
+
+bool LookAtModifier3D::is_using_angle_limitation() const {
+ return use_angle_limitation;
+}
+
+void LookAtModifier3D::set_symmetry_limitation(bool p_enabled) {
+ symmetry_limitation = p_enabled;
+ notify_property_list_changed();
+}
+
+bool LookAtModifier3D::is_limitation_symmetry() const {
+ return symmetry_limitation;
+}
+
+void LookAtModifier3D::set_primary_limit_angle(float p_angle) {
+ primary_limit_angle = p_angle;
+}
+
+float LookAtModifier3D::get_primary_limit_angle() const {
+ return primary_limit_angle;
+}
+
+void LookAtModifier3D::set_primary_damp_threshold(float p_power) {
+ primary_damp_threshold = p_power;
+}
+
+float LookAtModifier3D::get_primary_damp_threshold() const {
+ return primary_damp_threshold;
+}
+
+void LookAtModifier3D::set_primary_positive_limit_angle(float p_angle) {
+ primary_positive_limit_angle = p_angle;
+}
+
+float LookAtModifier3D::get_primary_positive_limit_angle() const {
+ return primary_positive_limit_angle;
+}
+
+void LookAtModifier3D::set_primary_positive_damp_threshold(float p_power) {
+ primary_positive_damp_threshold = p_power;
+}
+
+float LookAtModifier3D::get_primary_positive_damp_threshold() const {
+ return primary_positive_damp_threshold;
+}
+
+void LookAtModifier3D::set_primary_negative_limit_angle(float p_angle) {
+ primary_negative_limit_angle = p_angle;
+}
+
+float LookAtModifier3D::get_primary_negative_limit_angle() const {
+ return primary_negative_limit_angle;
+}
+
+void LookAtModifier3D::set_primary_negative_damp_threshold(float p_power) {
+ primary_negative_damp_threshold = p_power;
+}
+
+float LookAtModifier3D::get_primary_negative_damp_threshold() const {
+ return primary_negative_damp_threshold;
+}
+
+void LookAtModifier3D::set_secondary_limit_angle(float p_angle) {
+ secondary_limit_angle = p_angle;
+}
+
+float LookAtModifier3D::get_secondary_limit_angle() const {
+ return secondary_limit_angle;
+}
+
+void LookAtModifier3D::set_secondary_damp_threshold(float p_power) {
+ secondary_damp_threshold = p_power;
+}
+
+float LookAtModifier3D::get_secondary_damp_threshold() const {
+ return secondary_damp_threshold;
+}
+
+void LookAtModifier3D::set_secondary_positive_limit_angle(float p_angle) {
+ secondary_positive_limit_angle = p_angle;
+}
+
+float LookAtModifier3D::get_secondary_positive_limit_angle() const {
+ return secondary_positive_limit_angle;
+}
+
+void LookAtModifier3D::set_secondary_positive_damp_threshold(float p_power) {
+ secondary_positive_damp_threshold = p_power;
+}
+
+float LookAtModifier3D::get_secondary_positive_damp_threshold() const {
+ return secondary_positive_damp_threshold;
+}
+
+void LookAtModifier3D::set_secondary_negative_limit_angle(float p_angle) {
+ secondary_negative_limit_angle = p_angle;
+}
+
+float LookAtModifier3D::get_secondary_negative_limit_angle() const {
+ return secondary_negative_limit_angle;
+}
+
+void LookAtModifier3D::set_secondary_negative_damp_threshold(float p_power) {
+ secondary_negative_damp_threshold = p_power;
+}
+
+float LookAtModifier3D::get_secondary_negative_damp_threshold() const {
+ return secondary_negative_damp_threshold;
+}
+
+bool LookAtModifier3D::is_target_within_limitation() const {
+ return is_within_limitations;
+}
+
+float LookAtModifier3D::get_interpolation_remaining() const {
+ return remaining * duration;
+}
+
+bool LookAtModifier3D::is_interpolating() const {
+ return Math::is_zero_approx(remaining);
+}
+
+// General API.
+
+void LookAtModifier3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_target_node", "target_node"), &LookAtModifier3D::set_target_node);
+ ClassDB::bind_method(D_METHOD("get_target_node"), &LookAtModifier3D::get_target_node);
+
+ ClassDB::bind_method(D_METHOD("set_bone_name", "bone_name"), &LookAtModifier3D::set_bone_name);
+ ClassDB::bind_method(D_METHOD("get_bone_name"), &LookAtModifier3D::get_bone_name);
+ ClassDB::bind_method(D_METHOD("set_bone", "bone"), &LookAtModifier3D::set_bone);
+ ClassDB::bind_method(D_METHOD("get_bone"), &LookAtModifier3D::get_bone);
+ ClassDB::bind_method(D_METHOD("set_forward_axis", "forward_axis"), &LookAtModifier3D::set_forward_axis);
+ ClassDB::bind_method(D_METHOD("get_forward_axis"), &LookAtModifier3D::get_forward_axis);
+ ClassDB::bind_method(D_METHOD("set_primary_rotation_axis", "axis"), &LookAtModifier3D::set_primary_rotation_axis);
+ ClassDB::bind_method(D_METHOD("get_primary_rotation_axis"), &LookAtModifier3D::get_primary_rotation_axis);
+ ClassDB::bind_method(D_METHOD("set_use_secondary_rotation", "enabled"), &LookAtModifier3D::set_use_secondary_rotation);
+ ClassDB::bind_method(D_METHOD("is_using_secondary_rotation"), &LookAtModifier3D::is_using_secondary_rotation);
+ ClassDB::bind_method(D_METHOD("set_origin_safe_margin", "margin"), &LookAtModifier3D::set_origin_safe_margin);
+ ClassDB::bind_method(D_METHOD("get_origin_safe_margin"), &LookAtModifier3D::get_origin_safe_margin);
+
+ ClassDB::bind_method(D_METHOD("set_origin_from", "origin_from"), &LookAtModifier3D::set_origin_from);
+ ClassDB::bind_method(D_METHOD("get_origin_from"), &LookAtModifier3D::get_origin_from);
+ ClassDB::bind_method(D_METHOD("set_origin_bone_name", "bone_name"), &LookAtModifier3D::set_origin_bone_name);
+ ClassDB::bind_method(D_METHOD("get_origin_bone_name"), &LookAtModifier3D::get_origin_bone_name);
+ ClassDB::bind_method(D_METHOD("set_origin_bone", "bone"), &LookAtModifier3D::set_origin_bone);
+ ClassDB::bind_method(D_METHOD("get_origin_bone"), &LookAtModifier3D::get_origin_bone);
+ ClassDB::bind_method(D_METHOD("set_origin_external_node", "external_node"), &LookAtModifier3D::set_origin_external_node);
+ ClassDB::bind_method(D_METHOD("get_origin_external_node"), &LookAtModifier3D::get_origin_external_node);
+
+ ClassDB::bind_method(D_METHOD("set_origin_offset", "offset"), &LookAtModifier3D::set_origin_offset);
+ ClassDB::bind_method(D_METHOD("get_origin_offset"), &LookAtModifier3D::get_origin_offset);
+
+ ClassDB::bind_method(D_METHOD("set_duration", "duration"), &LookAtModifier3D::set_duration);
+ ClassDB::bind_method(D_METHOD("get_duration"), &LookAtModifier3D::get_duration);
+ ClassDB::bind_method(D_METHOD("set_transition_type", "transition_type"), &LookAtModifier3D::set_transition_type);
+ ClassDB::bind_method(D_METHOD("get_transition_type"), &LookAtModifier3D::get_transition_type);
+ ClassDB::bind_method(D_METHOD("set_ease_type", "ease_type"), &LookAtModifier3D::set_ease_type);
+ ClassDB::bind_method(D_METHOD("get_ease_type"), &LookAtModifier3D::get_ease_type);
+
+ ClassDB::bind_method(D_METHOD("set_use_angle_limitation", "enabled"), &LookAtModifier3D::set_use_angle_limitation);
+ ClassDB::bind_method(D_METHOD("is_using_angle_limitation"), &LookAtModifier3D::is_using_angle_limitation);
+ ClassDB::bind_method(D_METHOD("set_symmetry_limitation", "enabled"), &LookAtModifier3D::set_symmetry_limitation);
+ ClassDB::bind_method(D_METHOD("is_limitation_symmetry"), &LookAtModifier3D::is_limitation_symmetry);
+
+ ClassDB::bind_method(D_METHOD("set_primary_limit_angle", "angle"), &LookAtModifier3D::set_primary_limit_angle);
+ ClassDB::bind_method(D_METHOD("get_primary_limit_angle"), &LookAtModifier3D::get_primary_limit_angle);
+ ClassDB::bind_method(D_METHOD("set_primary_damp_threshold", "power"), &LookAtModifier3D::set_primary_damp_threshold);
+ ClassDB::bind_method(D_METHOD("get_primary_damp_threshold"), &LookAtModifier3D::get_primary_damp_threshold);
+
+ ClassDB::bind_method(D_METHOD("set_primary_positive_limit_angle", "angle"), &LookAtModifier3D::set_primary_positive_limit_angle);
+ ClassDB::bind_method(D_METHOD("get_primary_positive_limit_angle"), &LookAtModifier3D::get_primary_positive_limit_angle);
+ ClassDB::bind_method(D_METHOD("set_primary_positive_damp_threshold", "power"), &LookAtModifier3D::set_primary_positive_damp_threshold);
+ ClassDB::bind_method(D_METHOD("get_primary_positive_damp_threshold"), &LookAtModifier3D::get_primary_positive_damp_threshold);
+ ClassDB::bind_method(D_METHOD("set_primary_negative_limit_angle", "angle"), &LookAtModifier3D::set_primary_negative_limit_angle);
+ ClassDB::bind_method(D_METHOD("get_primary_negative_limit_angle"), &LookAtModifier3D::get_primary_negative_limit_angle);
+ ClassDB::bind_method(D_METHOD("set_primary_negative_damp_threshold", "power"), &LookAtModifier3D::set_primary_negative_damp_threshold);
+ ClassDB::bind_method(D_METHOD("get_primary_negative_damp_threshold"), &LookAtModifier3D::get_primary_negative_damp_threshold);
+
+ ClassDB::bind_method(D_METHOD("set_secondary_limit_angle", "angle"), &LookAtModifier3D::set_secondary_limit_angle);
+ ClassDB::bind_method(D_METHOD("get_secondary_limit_angle"), &LookAtModifier3D::get_secondary_limit_angle);
+ ClassDB::bind_method(D_METHOD("set_secondary_damp_threshold", "power"), &LookAtModifier3D::set_secondary_damp_threshold);
+ ClassDB::bind_method(D_METHOD("get_secondary_damp_threshold"), &LookAtModifier3D::get_secondary_damp_threshold);
+
+ ClassDB::bind_method(D_METHOD("set_secondary_positive_limit_angle", "angle"), &LookAtModifier3D::set_secondary_positive_limit_angle);
+ ClassDB::bind_method(D_METHOD("get_secondary_positive_limit_angle"), &LookAtModifier3D::get_secondary_positive_limit_angle);
+ ClassDB::bind_method(D_METHOD("set_secondary_positive_damp_threshold", "power"), &LookAtModifier3D::set_secondary_positive_damp_threshold);
+ ClassDB::bind_method(D_METHOD("get_secondary_positive_damp_threshold"), &LookAtModifier3D::get_secondary_positive_damp_threshold);
+ ClassDB::bind_method(D_METHOD("set_secondary_negative_limit_angle", "angle"), &LookAtModifier3D::set_secondary_negative_limit_angle);
+ ClassDB::bind_method(D_METHOD("get_secondary_negative_limit_angle"), &LookAtModifier3D::get_secondary_negative_limit_angle);
+ ClassDB::bind_method(D_METHOD("set_secondary_negative_damp_threshold", "power"), &LookAtModifier3D::set_secondary_negative_damp_threshold);
+ ClassDB::bind_method(D_METHOD("get_secondary_negative_damp_threshold"), &LookAtModifier3D::get_secondary_negative_damp_threshold);
+
+ ClassDB::bind_method(D_METHOD("get_interpolation_remaining"), &LookAtModifier3D::get_interpolation_remaining);
+ ClassDB::bind_method(D_METHOD("is_interpolating"), &LookAtModifier3D::is_interpolating);
+ ClassDB::bind_method(D_METHOD("is_target_within_limitation"), &LookAtModifier3D::is_target_within_limitation);
+
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_node", PROPERTY_HINT_NODE_TYPE, "Node3D"), "set_target_node", "get_target_node");
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "bone_name", PROPERTY_HINT_ENUM_SUGGESTION, ""), "set_bone_name", "get_bone_name");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "bone", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_bone", "get_bone");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "forward_axis", PROPERTY_HINT_ENUM, "+X,-X,+Y,-Y,+Z,-Z"), "set_forward_axis", "get_forward_axis");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "primary_rotation_axis", PROPERTY_HINT_ENUM, "X,Y,Z"), "set_primary_rotation_axis", "get_primary_rotation_axis");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_secondary_rotation"), "set_use_secondary_rotation", "is_using_secondary_rotation");
+
+ ADD_GROUP("Origin Settings", "origin_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "origin_from", PROPERTY_HINT_ENUM, "Self,SpecificBone,ExternalNode"), "set_origin_from", "get_origin_from");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "origin_bone_name", PROPERTY_HINT_ENUM_SUGGESTION, ""), "set_origin_bone_name", "get_origin_bone_name");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "origin_bone", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_origin_bone", "get_origin_bone");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "origin_external_node", PROPERTY_HINT_NODE_TYPE, "Node3D"), "set_origin_external_node", "get_origin_external_node");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "origin_offset"), "set_origin_offset", "get_origin_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "origin_safe_margin", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater,suffix:m"), "set_origin_safe_margin", "get_origin_safe_margin");
+
+ ADD_GROUP("Time Based Interpolation", "");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "duration", PROPERTY_HINT_RANGE, "0,10,0.001,or_greater,suffix:s"), "set_duration", "get_duration");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "transition_type", PROPERTY_HINT_ENUM, "Linear,Sine,Quint,Quart,Quad,Expo,Elastic,Cubic,Circ,Bounce,Back,Spring"), "set_transition_type", "get_transition_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "ease_type", PROPERTY_HINT_ENUM, "In,Out,InOut,OutIn"), "set_ease_type", "get_ease_type");
+
+ ADD_GROUP("Angle Limitation", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_angle_limitation"), "set_use_angle_limitation", "is_using_angle_limitation");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "symmetry_limitation"), "set_symmetry_limitation", "is_limitation_symmetry");
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "primary_limit_angle", PROPERTY_HINT_RANGE, "0,360,0.01,radians_as_degrees"), "set_primary_limit_angle", "get_primary_limit_angle");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "primary_damp_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_primary_damp_threshold", "get_primary_damp_threshold");
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "primary_positive_limit_angle", PROPERTY_HINT_RANGE, "0,180,0.01,radians_as_degrees"), "set_primary_positive_limit_angle", "get_primary_positive_limit_angle");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "primary_positive_damp_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_primary_positive_damp_threshold", "get_primary_positive_damp_threshold");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "primary_negative_limit_angle", PROPERTY_HINT_RANGE, "0,180,0.01,radians_as_degrees"), "set_primary_negative_limit_angle", "get_primary_negative_limit_angle");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "primary_negative_damp_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_primary_negative_damp_threshold", "get_primary_negative_damp_threshold");
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "secondary_limit_angle", PROPERTY_HINT_RANGE, "0,360,0.01,radians_as_degrees"), "set_secondary_limit_angle", "get_secondary_limit_angle");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "secondary_damp_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_secondary_damp_threshold", "get_secondary_damp_threshold");
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "secondary_positive_limit_angle", PROPERTY_HINT_RANGE, "0,180,0.01,radians_as_degrees"), "set_secondary_positive_limit_angle", "get_secondary_positive_limit_angle");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "secondary_positive_damp_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_secondary_positive_damp_threshold", "get_secondary_positive_damp_threshold");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "secondary_negative_limit_angle", PROPERTY_HINT_RANGE, "0,180,0.01,radians_as_degrees"), "set_secondary_negative_limit_angle", "get_secondary_negative_limit_angle");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "secondary_negative_damp_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_secondary_negative_damp_threshold", "get_secondary_negative_damp_threshold");
+
+ BIND_ENUM_CONSTANT(BONE_AXIS_PLUS_X);
+ BIND_ENUM_CONSTANT(BONE_AXIS_MINUS_X);
+ BIND_ENUM_CONSTANT(BONE_AXIS_PLUS_Y);
+ BIND_ENUM_CONSTANT(BONE_AXIS_MINUS_Y);
+ BIND_ENUM_CONSTANT(BONE_AXIS_PLUS_Z);
+ BIND_ENUM_CONSTANT(BONE_AXIS_MINUS_Z);
+
+ BIND_ENUM_CONSTANT(ORIGIN_FROM_SELF);
+ BIND_ENUM_CONSTANT(ORIGIN_FROM_SPECIFIC_BONE);
+ BIND_ENUM_CONSTANT(ORIGIN_FROM_EXTERNAL_NODE);
+}
+
+void LookAtModifier3D::_process_modification() {
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ Skeleton3D *skeleton = get_skeleton();
+ if (!skeleton || bone < 0 || bone >= skeleton->get_bone_count()) {
+ return;
+ }
+
+ // Calculate bone rest space in the world.
+ Transform3D bone_rest_space;
+ int parent_bone = skeleton->get_bone_parent(bone);
+ if (parent_bone < 0) {
+ bone_rest_space = skeleton->get_global_transform() * skeleton->get_bone_rest(bone);
+ } else {
+ bone_rest_space = skeleton->get_global_transform() * skeleton->get_bone_global_pose(parent_bone) * skeleton->get_bone_rest(bone);
+ }
+
+ // Calculate forward_vector and destination.
+ is_within_limitations = true;
+ Vector3 prev_forward_vector = forward_vector;
+ Quaternion destination;
+ Node3D *target = Object::cast_to<Node3D>(get_node_or_null(target_node));
+ if (!target) {
+ destination = skeleton->get_bone_pose_rotation(bone);
+ } else {
+ Transform3D origin_tr;
+ if (origin_from == ORIGIN_FROM_SPECIFIC_BONE && origin_bone >= 0 && origin_bone < skeleton->get_bone_count()) {
+ origin_tr = skeleton->get_global_transform() * skeleton->get_bone_global_pose(origin_bone);
+ } else if (origin_from == ORIGIN_FROM_EXTERNAL_NODE) {
+ Node3D *origin_src = Object::cast_to<Node3D>(get_node_or_null(origin_external_node));
+ if (origin_src) {
+ origin_tr = origin_src->get_global_transform();
+ } else {
+ origin_tr = bone_rest_space;
+ }
+ } else {
+ origin_tr = bone_rest_space;
+ }
+ forward_vector = bone_rest_space.orthonormalized().basis.xform_inv((target->get_global_position() - origin_tr.translated_local(origin_offset).origin));
+ forward_vector_nrm = forward_vector.normalized();
+ if (forward_vector_nrm.abs().is_equal_approx(get_vector_from_axis(primary_rotation_axis))) {
+ destination = skeleton->get_bone_pose_rotation(bone);
+ forward_vector = Vector3(0, 0, 0); // The zero-vector to be used for checking in the line immediately below to avoid animation glitch.
+ } else {
+ destination = look_at_with_axes(skeleton->get_bone_rest(bone)).basis.get_rotation_quaternion();
+ }
+ }
+
+ // Detect flipping.
+ bool is_not_max_influence = influence < 1.0;
+ bool is_flippable = use_angle_limitation || is_not_max_influence;
+ Vector3::Axis current_forward_axis = get_axis_from_bone_axis(forward_axis);
+ if (is_intersecting_axis(prev_forward_vector, forward_vector, current_forward_axis, secondary_rotation_axis) ||
+ is_intersecting_axis(prev_forward_vector, forward_vector, primary_rotation_axis, primary_rotation_axis, true) ||
+ is_intersecting_axis(prev_forward_vector, forward_vector, secondary_rotation_axis, current_forward_axis) ||
+ (prev_forward_vector != Vector3(0, 0, 0) && forward_vector == Vector3(0, 0, 0)) ||
+ (prev_forward_vector == Vector3(0, 0, 0) && forward_vector != Vector3(0, 0, 0))) {
+ init_transition();
+ } else if (is_flippable && signbit(prev_forward_vector[secondary_rotation_axis]) != signbit(forward_vector[secondary_rotation_axis])) {
+ // Flipping by angle_limitation can be detected by sign of secondary rotation axes during forward_vector is rotated more than 90 degree from forward_axis (means dot production is negative).
+ Vector3 prev_forward_vector_nrm = forward_vector.normalized();
+ Vector3 rest_forward_vector = get_vector_from_bone_axis(forward_axis);
+ if (symmetry_limitation) {
+ if ((is_not_max_influence || !Math::is_equal_approx(primary_limit_angle, (float)Math_TAU)) &&
+ prev_forward_vector_nrm.dot(rest_forward_vector) < 0 &&
+ forward_vector_nrm.dot(rest_forward_vector) < 0) {
+ init_transition();
+ }
+ } else {
+ if ((is_not_max_influence || !Math::is_equal_approx(primary_positive_limit_angle + primary_negative_limit_angle, (float)Math_TAU)) &&
+ prev_forward_vector_nrm.dot(rest_forward_vector) < 0 &&
+ forward_vector_nrm.dot(rest_forward_vector) < 0) {
+ init_transition();
+ }
+ }
+ }
+
+ // Do time-based interpolation.
+ if (remaining > 0) {
+ double delta = 0.0;
+ if (skeleton->get_modifier_callback_mode_process() == Skeleton3D::MODIFIER_CALLBACK_MODE_PROCESS_IDLE) {
+ delta = get_process_delta_time();
+ } else {
+ delta = get_physics_process_delta_time();
+ }
+ remaining = MAX(0, remaining - time_step * delta);
+ if (is_flippable) {
+ // Interpolate through the rest same as AnimationTree blending for preventing to penetrate the bone into the body.
+ Quaternion rest = skeleton->get_bone_rest(bone).basis.get_rotation_quaternion();
+ float weight = Tween::run_equation(transition_type, ease_type, 1 - remaining, 0.0, 1.0, 1.0);
+ destination = rest * Quaternion().slerp(rest.inverse() * from_q, 1 - weight) * Quaternion().slerp(rest.inverse() * destination, weight);
+ } else {
+ destination = from_q.slerp(destination, Tween::run_equation(transition_type, ease_type, 1 - remaining, 0.0, 1.0, 1.0));
+ }
+ }
+
+ skeleton->set_bone_pose_rotation(bone, destination);
+ prev_q = destination;
+}
+
+bool LookAtModifier3D::is_intersecting_axis(const Vector3 &p_prev, const Vector3 &p_current, Vector3::Axis p_flipping_axis, Vector3::Axis p_check_axis, bool p_check_plane) const {
+ // Prevent that the angular velocity does not become too large.
+ // Check that is p_flipping_axis flipped nearby p_check_axis (close than origin_safe_margin) or not. If p_check_plane is true, check two axes of crossed plane.
+ if (p_check_plane) {
+ if (get_projection_vector(p_prev, p_check_axis).length() > origin_safe_margin && get_projection_vector(p_current, p_check_axis).length() > origin_safe_margin) {
+ return false;
+ }
+ } else if (Math::abs(p_prev[p_check_axis]) > origin_safe_margin && Math::abs(p_current[p_check_axis]) > origin_safe_margin) {
+ return false;
+ }
+
+ return signbit(p_prev[p_flipping_axis]) != signbit(p_current[p_flipping_axis]);
+}
+
+Vector3 LookAtModifier3D::get_basis_vector_from_bone_axis(const Basis &p_basis, LookAtModifier3D::BoneAxis p_axis) const {
+ Vector3 ret;
+ switch (p_axis) {
+ case BONE_AXIS_PLUS_X: {
+ ret = p_basis.get_column(0);
+ } break;
+ case BONE_AXIS_MINUS_X: {
+ ret = -p_basis.get_column(0);
+ } break;
+ case BONE_AXIS_PLUS_Y: {
+ ret = p_basis.get_column(1);
+ } break;
+ case BONE_AXIS_MINUS_Y: {
+ ret = -p_basis.get_column(1);
+ } break;
+ case BONE_AXIS_PLUS_Z: {
+ ret = p_basis.get_column(2);
+ } break;
+ case BONE_AXIS_MINUS_Z: {
+ ret = -p_basis.get_column(2);
+ } break;
+ }
+ return ret;
+}
+
+Vector3 LookAtModifier3D::get_vector_from_bone_axis(const LookAtModifier3D::BoneAxis &p_axis) const {
+ Vector3 ret;
+ switch (p_axis) {
+ case BONE_AXIS_PLUS_X: {
+ ret = Vector3(1, 0, 0);
+ } break;
+ case BONE_AXIS_MINUS_X: {
+ ret = Vector3(-1, 0, 0);
+ } break;
+ case BONE_AXIS_PLUS_Y: {
+ ret = Vector3(0, 1, 0);
+ } break;
+ case BONE_AXIS_MINUS_Y: {
+ ret = Vector3(0, -1, 0);
+ } break;
+ case BONE_AXIS_PLUS_Z: {
+ ret = Vector3(0, 0, 1);
+ } break;
+ case BONE_AXIS_MINUS_Z: {
+ ret = Vector3(0, 0, -1);
+ } break;
+ }
+ return ret;
+}
+
+Vector3 LookAtModifier3D::get_vector_from_axis(const Vector3::Axis &p_axis) const {
+ Vector3 ret;
+ switch (p_axis) {
+ case Vector3::AXIS_X: {
+ ret = Vector3(1, 0, 0);
+ } break;
+ case Vector3::AXIS_Y: {
+ ret = Vector3(0, 1, 0);
+ } break;
+ case Vector3::AXIS_Z: {
+ ret = Vector3(0, 0, 1);
+ } break;
+ }
+ return ret;
+}
+
+Vector3::Axis LookAtModifier3D::get_axis_from_bone_axis(BoneAxis p_axis) const {
+ Vector3::Axis ret = Vector3::AXIS_X;
+ switch (p_axis) {
+ case BONE_AXIS_PLUS_X:
+ case BONE_AXIS_MINUS_X: {
+ ret = Vector3::AXIS_X;
+ } break;
+ case BONE_AXIS_PLUS_Y:
+ case BONE_AXIS_MINUS_Y: {
+ ret = Vector3::AXIS_Y;
+ } break;
+ case BONE_AXIS_PLUS_Z:
+ case BONE_AXIS_MINUS_Z: {
+ ret = Vector3::AXIS_Z;
+ } break;
+ }
+ return ret;
+}
+
+Vector2 LookAtModifier3D::get_projection_vector(const Vector3 &p_vector, Vector3::Axis p_axis) const {
+ // NOTE: axis is swapped between 2D and 3D.
+ Vector2 ret;
+ switch (p_axis) {
+ case Vector3::AXIS_X: {
+ ret = Vector2(p_vector.z, p_vector.y);
+ } break;
+ case Vector3::AXIS_Y: {
+ ret = Vector2(p_vector.x, p_vector.z);
+ } break;
+ case Vector3::AXIS_Z: {
+ ret = Vector2(p_vector.y, p_vector.x);
+ } break;
+ }
+ return ret;
+}
+
+float LookAtModifier3D::remap_damped(float p_from, float p_to, float p_damp_threshold, float p_value) const {
+ float sign = signbit(p_value) ? -1.0f : 1.0f;
+ float abs_value = Math::abs(p_value);
+
+ if (Math::is_equal_approx(p_damp_threshold, 1.0f) || Math::is_zero_approx(p_to)) {
+ return sign * CLAMP(abs_value, p_from, p_to); // Avoid division by zero.
+ }
+
+ float value = Math::inverse_lerp(p_from, p_to, abs_value);
+
+ if (value <= p_damp_threshold) {
+ return sign * CLAMP(abs_value, p_from, p_to);
+ }
+
+ double limit = Math_PI;
+ double inv_to = 1.0 / p_to;
+ double end_x = limit * inv_to;
+ double position = abs_value * inv_to;
+ Vector2 start = Vector2(p_damp_threshold, p_damp_threshold);
+ Vector2 mid = Vector2(1.0, 1.0);
+ Vector2 end = Vector2(end_x, 1.0);
+ value = get_bspline_y(start, mid, end, position);
+
+ return sign * Math::lerp(p_from, p_to, value);
+}
+
+double LookAtModifier3D::get_bspline_y(const Vector2 &p_from, const Vector2 &p_control, const Vector2 &p_to, double p_x) const {
+ double a = p_from.x - 2.0 * p_control.x + p_to.x;
+ double b = -2.0 * p_from.x + 2.0 * p_control.x;
+ double c = p_from.x - p_x;
+ double t = 0.0;
+ if (Math::is_zero_approx(a)) {
+ t = -c / b; // Almost linear.
+ } else {
+ double discriminant = b * b - 4.0 * a * c;
+ double sqrt_discriminant = Math::sqrt(discriminant);
+ double e = 1.0 / (2.0 * a);
+ double t1 = (-b + sqrt_discriminant) * e;
+ t = (0.0 <= t1 && t1 <= 1.0) ? t1 : (-b - sqrt_discriminant) * e;
+ }
+ double u = 1.0 - t;
+ double y = u * u * p_from.y + 2.0 * u * t * p_control.y + t * t * p_to.y;
+ return y;
+}
+
+Transform3D LookAtModifier3D::look_at_with_axes(const Transform3D &p_rest) {
+ // Primary rotation by projection to 2D plane by xform_inv and picking elements.
+ Vector3 current_vector = get_basis_vector_from_bone_axis(p_rest.basis, forward_axis).normalized();
+ Vector2 src_vec2 = get_projection_vector(p_rest.basis.xform_inv(forward_vector_nrm), primary_rotation_axis).normalized();
+ Vector2 dst_vec2 = get_projection_vector(p_rest.basis.xform_inv(current_vector), primary_rotation_axis).normalized();
+ real_t calculated_angle = src_vec2.angle_to(dst_vec2);
+ Transform3D primary_result = p_rest.rotated_local(get_vector_from_axis(primary_rotation_axis), calculated_angle);
+ Transform3D current_result = primary_result; // primary_result will be used by calculation of secondary rotation, current_result is rotated by that.
+ float limit_angle = 0.0;
+ float damp_threshold = 0.0;
+
+ if (use_angle_limitation) {
+ if (symmetry_limitation) {
+ limit_angle = primary_limit_angle * 0.5f;
+ damp_threshold = primary_damp_threshold;
+ } else {
+ if (signbit(calculated_angle)) {
+ limit_angle = primary_negative_limit_angle;
+ damp_threshold = primary_negative_damp_threshold;
+ } else {
+ limit_angle = primary_positive_limit_angle;
+ damp_threshold = primary_positive_damp_threshold;
+ }
+ }
+ if (Math::abs(calculated_angle) > limit_angle) {
+ is_within_limitations = false;
+ }
+ calculated_angle = remap_damped(0, limit_angle, damp_threshold, calculated_angle);
+ current_result = p_rest.rotated_local(get_vector_from_axis(primary_rotation_axis), calculated_angle);
+ }
+
+ // Needs for detecting flipping even if use_secondary_rotation is false.
+ Vector3 secondary_plane = get_vector_from_bone_axis(forward_axis) + get_vector_from_axis(primary_rotation_axis);
+ secondary_rotation_axis = Math::is_zero_approx(secondary_plane.x) ? Vector3::AXIS_X : (Math::is_zero_approx(secondary_plane.y) ? Vector3::AXIS_Y : Vector3::AXIS_Z);
+
+ if (!use_secondary_rotation) {
+ return current_result;
+ }
+
+ // Secondary rotation by projection to 2D plane by xform_inv and picking elements.
+ current_vector = get_basis_vector_from_bone_axis(primary_result.basis, forward_axis).normalized();
+ src_vec2 = get_projection_vector(primary_result.basis.xform_inv(forward_vector_nrm), secondary_rotation_axis).normalized();
+ dst_vec2 = get_projection_vector(primary_result.basis.xform_inv(current_vector), secondary_rotation_axis).normalized();
+ calculated_angle = src_vec2.angle_to(dst_vec2);
+
+ if (use_angle_limitation) {
+ if (symmetry_limitation) {
+ limit_angle = secondary_limit_angle * 0.5f;
+ damp_threshold = secondary_damp_threshold;
+ } else {
+ if (signbit(calculated_angle)) {
+ limit_angle = secondary_negative_limit_angle;
+ damp_threshold = secondary_negative_damp_threshold;
+ } else {
+ limit_angle = secondary_positive_limit_angle;
+ damp_threshold = secondary_positive_damp_threshold;
+ }
+ }
+ if (Math::abs(calculated_angle) > limit_angle) {
+ is_within_limitations = false;
+ }
+ calculated_angle = remap_damped(0, limit_angle, damp_threshold, calculated_angle);
+ }
+
+ current_result = current_result.rotated_local(get_vector_from_axis(secondary_rotation_axis), calculated_angle);
+
+ return current_result;
+}
+
+void LookAtModifier3D::init_transition() {
+ if (Math::is_zero_approx(duration)) {
+ return;
+ }
+ from_q = prev_q;
+ remaining = 1.0;
+}
diff --git a/scene/3d/look_at_modifier_3d.h b/scene/3d/look_at_modifier_3d.h
new file mode 100644
index 0000000000..9329edf3c9
--- /dev/null
+++ b/scene/3d/look_at_modifier_3d.h
@@ -0,0 +1,205 @@
+/**************************************************************************/
+/* look_at_modifier_3d.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef LOOK_AT_MODIFIER_3D_H
+#define LOOK_AT_MODIFIER_3D_H
+
+#include "scene/3d/skeleton_modifier_3d.h"
+#include "scene/animation/tween.h"
+
+class LookAtModifier3D : public SkeletonModifier3D {
+ GDCLASS(LookAtModifier3D, SkeletonModifier3D);
+
+public:
+ enum BoneAxis {
+ BONE_AXIS_PLUS_X,
+ BONE_AXIS_MINUS_X,
+ BONE_AXIS_PLUS_Y,
+ BONE_AXIS_MINUS_Y,
+ BONE_AXIS_PLUS_Z,
+ BONE_AXIS_MINUS_Z,
+ };
+
+ enum OriginFrom {
+ ORIGIN_FROM_SELF,
+ ORIGIN_FROM_SPECIFIC_BONE,
+ ORIGIN_FROM_EXTERNAL_NODE,
+ };
+
+private:
+ String bone_name;
+ int bone = -1;
+
+ Vector3 forward_vector;
+ Vector3 forward_vector_nrm;
+ BoneAxis forward_axis = BONE_AXIS_PLUS_Z;
+ Vector3::Axis primary_rotation_axis = Vector3::AXIS_Y;
+ Vector3::Axis secondary_rotation_axis = Vector3::AXIS_X;
+ bool use_secondary_rotation = true;
+
+ OriginFrom origin_from = ORIGIN_FROM_SELF;
+ String origin_bone_name;
+ int origin_bone = -1;
+ NodePath origin_external_node;
+
+ Vector3 origin_offset;
+ float origin_safe_margin = 0.1;
+
+ NodePath target_node;
+
+ float duration = 0;
+ Tween::TransitionType transition_type = Tween::TRANS_LINEAR;
+ Tween::EaseType ease_type = Tween::EASE_IN;
+
+ bool use_angle_limitation = false;
+ bool symmetry_limitation = true;
+
+ float primary_limit_angle = Math_TAU;
+ float primary_damp_threshold = 1.0f;
+ float primary_positive_limit_angle = Math_PI;
+ float primary_positive_damp_threshold = 1.0f;
+ float primary_negative_limit_angle = Math_PI;
+ float primary_negative_damp_threshold = 1.0f;
+
+ float secondary_limit_angle = Math_TAU;
+ float secondary_damp_threshold = 1.0f;
+ float secondary_positive_limit_angle = Math_PI;
+ float secondary_positive_damp_threshold = 1.0f;
+ float secondary_negative_limit_angle = Math_PI;
+ float secondary_negative_damp_threshold = 1.0f;
+
+ bool is_within_limitations = false;
+
+ // For time-based interpolation.
+ Quaternion from_q;
+ Quaternion prev_q;
+
+ float remaining = 0;
+ float time_step = 1.0;
+
+ Vector3 get_basis_vector_from_bone_axis(const Basis &p_basis, BoneAxis p_axis) const;
+ Vector3 get_vector_from_bone_axis(const BoneAxis &p_axis) const;
+ Vector3 get_vector_from_axis(const Vector3::Axis &p_axis) const;
+ Vector3::Axis get_axis_from_bone_axis(BoneAxis p_axis) const;
+ Vector2 get_projection_vector(const Vector3 &p_vector, Vector3::Axis p_axis) const;
+ float remap_damped(float p_from, float p_to, float p_damp_threshold, float p_value) const;
+ double get_bspline_y(const Vector2 &p_from, const Vector2 &p_control, const Vector2 &p_to, double p_x) const;
+ bool is_intersecting_axis(const Vector3 &p_prev, const Vector3 &p_current, Vector3::Axis p_flipping_axis, Vector3::Axis p_check_axis, bool p_check_plane = false) const;
+
+ Transform3D look_at_with_axes(const Transform3D &p_rest);
+ void init_transition();
+
+protected:
+ virtual PackedStringArray get_configuration_warnings() const override;
+ void _validate_property(PropertyInfo &p_property) const;
+
+ static void _bind_methods();
+
+ virtual void _process_modification() override;
+
+public:
+ void set_bone_name(const String &p_bone_name);
+ String get_bone_name() const;
+ void set_bone(int p_bone);
+ int get_bone() const;
+
+ void set_forward_axis(BoneAxis p_axis);
+ BoneAxis get_forward_axis() const;
+ void set_primary_rotation_axis(Vector3::Axis p_axis);
+ Vector3::Axis get_primary_rotation_axis() const;
+ void set_use_secondary_rotation(bool p_enabled);
+ bool is_using_secondary_rotation() const;
+
+ void set_origin_from(OriginFrom p_origin_from);
+ OriginFrom get_origin_from() const;
+ void set_origin_bone_name(const String &p_bone_name);
+ String get_origin_bone_name() const;
+ void set_origin_bone(int p_bone);
+ int get_origin_bone() const;
+ void set_origin_external_node(const NodePath &p_external_node);
+ NodePath get_origin_external_node() const;
+
+ void set_origin_offset(const Vector3 &p_offset);
+ Vector3 get_origin_offset() const;
+ void set_origin_safe_margin(float p_margin);
+ float get_origin_safe_margin() const;
+
+ void set_target_node(const NodePath &p_target_node);
+ NodePath get_target_node() const;
+
+ void set_duration(float p_duration);
+ float get_duration() const;
+ void set_transition_type(Tween::TransitionType p_transition_type);
+ Tween::TransitionType get_transition_type() const;
+ void set_ease_type(Tween::EaseType p_ease_type);
+ Tween::EaseType get_ease_type() const;
+
+ void set_use_angle_limitation(bool p_enabled);
+ bool is_using_angle_limitation() const;
+ void set_symmetry_limitation(bool p_enabled);
+ bool is_limitation_symmetry() const;
+
+ void set_primary_limit_angle(float p_angle);
+ float get_primary_limit_angle() const;
+ void set_primary_damp_threshold(float p_power);
+ float get_primary_damp_threshold() const;
+
+ void set_primary_positive_limit_angle(float p_angle);
+ float get_primary_positive_limit_angle() const;
+ void set_primary_positive_damp_threshold(float p_power);
+ float get_primary_positive_damp_threshold() const;
+ void set_primary_negative_limit_angle(float p_angle);
+ float get_primary_negative_limit_angle() const;
+ void set_primary_negative_damp_threshold(float p_power);
+ float get_primary_negative_damp_threshold() const;
+
+ void set_secondary_limit_angle(float p_angle);
+ float get_secondary_limit_angle() const;
+ void set_secondary_damp_threshold(float p_power);
+ float get_secondary_damp_threshold() const;
+
+ void set_secondary_positive_limit_angle(float p_angle);
+ float get_secondary_positive_limit_angle() const;
+ void set_secondary_positive_damp_threshold(float p_power);
+ float get_secondary_positive_damp_threshold() const;
+ void set_secondary_negative_limit_angle(float p_angle);
+ float get_secondary_negative_limit_angle() const;
+ void set_secondary_negative_damp_threshold(float p_power);
+ float get_secondary_negative_damp_threshold() const;
+
+ float get_interpolation_remaining() const;
+ bool is_interpolating() const;
+ bool is_target_within_limitation() const;
+};
+
+VARIANT_ENUM_CAST(LookAtModifier3D::BoneAxis);
+VARIANT_ENUM_CAST(LookAtModifier3D::OriginFrom);
+
+#endif // LOOK_AT_MODIFIER_3D_H
diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
index f551cb401c..14bc22a217 100644
--- a/scene/3d/mesh_instance_3d.cpp
+++ b/scene/3d/mesh_instance_3d.cpp
@@ -87,17 +87,9 @@ bool MeshInstance3D::_get(const StringName &p_name, Variant &r_ret) const {
}
void MeshInstance3D::_get_property_list(List<PropertyInfo> *p_list) const {
- List<String> ls;
- for (const KeyValue<StringName, int> &E : blend_shape_properties) {
- ls.push_back(E.key);
- }
-
- ls.sort();
-
- for (const String &E : ls) {
- p_list->push_back(PropertyInfo(Variant::FLOAT, E, PROPERTY_HINT_RANGE, "-1,1,0.00001"));
+ for (uint32_t i = 0; i < blend_shape_tracks.size(); i++) {
+ p_list->push_back(PropertyInfo(Variant::FLOAT, vformat("blend_shapes/%s", String(mesh->get_blend_shape_name(i))), PROPERTY_HINT_RANGE, "-1,1,0.00001"));
}
-
if (mesh.is_valid()) {
for (int i = 0; i < mesh->get_surface_count(); i++) {
p_list->push_back(PropertyInfo(Variant::OBJECT, vformat("%s/%d", PNAME("surface_material_override"), i), PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial", PROPERTY_USAGE_DEFAULT));
@@ -142,6 +134,7 @@ int MeshInstance3D::get_blend_shape_count() const {
}
return mesh->get_blend_shape_count();
}
+
int MeshInstance3D::find_blend_shape_by_name(const StringName &p_name) {
if (mesh.is_null()) {
return -1;
@@ -153,11 +146,13 @@ int MeshInstance3D::find_blend_shape_by_name(const StringName &p_name) {
}
return -1;
}
+
float MeshInstance3D::get_blend_shape_value(int p_blend_shape) const {
ERR_FAIL_COND_V(mesh.is_null(), 0.0);
ERR_FAIL_INDEX_V(p_blend_shape, (int)blend_shape_tracks.size(), 0);
return blend_shape_tracks[p_blend_shape];
}
+
void MeshInstance3D::set_blend_shape_value(int p_blend_shape, float p_value) {
ERR_FAIL_COND(mesh.is_null());
ERR_FAIL_INDEX(p_blend_shape, (int)blend_shape_tracks.size());
diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp
index 0735d5dde5..7be01589f4 100644
--- a/scene/3d/navigation_obstacle_3d.cpp
+++ b/scene/3d/navigation_obstacle_3d.cpp
@@ -92,30 +92,26 @@ void NavigationObstacle3D::_notification(int p_what) {
} else {
_update_map(RID());
}
- previous_transform = get_global_transform();
// need to trigger map controlled agent assignment somehow for the fake_agent since obstacles use no callback like regular agents
NavigationServer3D::get_singleton()->obstacle_set_avoidance_enabled(obstacle, avoidance_enabled);
- _update_position(get_global_transform().origin);
+ _update_transform();
set_physics_process_internal(true);
#ifdef DEBUG_ENABLED
- if ((NavigationServer3D::get_singleton()->get_debug_avoidance_enabled()) &&
- (NavigationServer3D::get_singleton()->get_debug_navigation_avoidance_enable_obstacles_radius())) {
- _update_fake_agent_radius_debug();
- _update_static_obstacle_debug();
- }
+ _update_debug();
#endif // DEBUG_ENABLED
} break;
+#ifdef TOOLS_ENABLED
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+ update_gizmos();
+ } break;
+#endif // TOOLS_ENABLED
+
case NOTIFICATION_EXIT_TREE: {
set_physics_process_internal(false);
_update_map(RID());
#ifdef DEBUG_ENABLED
- if (fake_agent_radius_debug_instance.is_valid()) {
- RS::get_singleton()->instance_set_visible(fake_agent_radius_debug_instance, false);
- }
- if (static_obstacle_debug_instance.is_valid()) {
- RS::get_singleton()->instance_set_visible(static_obstacle_debug_instance, false);
- }
+ _update_debug();
#endif // DEBUG_ENABLED
} break;
@@ -151,20 +147,13 @@ void NavigationObstacle3D::_notification(int p_what) {
#ifdef DEBUG_ENABLED
case NOTIFICATION_VISIBILITY_CHANGED: {
- if (is_inside_tree()) {
- if (fake_agent_radius_debug_instance.is_valid()) {
- RS::get_singleton()->instance_set_visible(fake_agent_radius_debug_instance, is_visible_in_tree());
- }
- if (static_obstacle_debug_instance.is_valid()) {
- RS::get_singleton()->instance_set_visible(static_obstacle_debug_instance, is_visible_in_tree());
- }
- }
+ _update_debug();
} break;
#endif // DEBUG_ENABLED
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (is_inside_tree()) {
- _update_position(get_global_transform().origin);
+ _update_transform();
if (velocity_submitted) {
velocity_submitted = false;
@@ -175,21 +164,23 @@ void NavigationObstacle3D::_notification(int p_what) {
previous_velocity = velocity;
}
#ifdef DEBUG_ENABLED
- if (fake_agent_radius_debug_instance.is_valid() && radius > 0.0) {
+ if (fake_agent_radius_debug_instance_rid.is_valid() && radius > 0.0) {
// Prevent non-positive scaling.
const Vector3 safe_scale = get_global_basis().get_scale().abs().maxf(0.001);
// Agent radius is a scalar value and does not support non-uniform scaling, choose the largest axis.
const float scaling_max_value = safe_scale[safe_scale.max_axis_index()];
const Vector3 uniform_max_scale = Vector3(scaling_max_value, scaling_max_value, scaling_max_value);
const Transform3D debug_transform = Transform3D(Basis().scaled(uniform_max_scale), get_global_position());
- RS::get_singleton()->instance_set_transform(fake_agent_radius_debug_instance, debug_transform);
+
+ RS::get_singleton()->instance_set_transform(fake_agent_radius_debug_instance_rid, debug_transform);
}
- if (static_obstacle_debug_instance.is_valid() && get_vertices().size() > 0) {
+ if (static_obstacle_debug_instance_rid.is_valid() && get_vertices().size() > 0) {
// Prevent non-positive scaling.
const Vector3 safe_scale = get_global_basis().get_scale().abs().maxf(0.001);
// Obstacles are projected to the xz-plane, so only rotation around the y-axis can be taken into account.
const Transform3D debug_transform = Transform3D(Basis().scaled(safe_scale).rotated(Vector3(0.0, 1.0, 0.0), get_global_rotation().y), get_global_position());
- RS::get_singleton()->instance_set_transform(static_obstacle_debug_instance, debug_transform);
+
+ RS::get_singleton()->instance_set_transform(static_obstacle_debug_instance_rid, debug_transform);
}
#endif // DEBUG_ENABLED
}
@@ -198,53 +189,83 @@ void NavigationObstacle3D::_notification(int p_what) {
}
NavigationObstacle3D::NavigationObstacle3D() {
- obstacle = NavigationServer3D::get_singleton()->obstacle_create();
+ NavigationServer3D *ns3d = NavigationServer3D::get_singleton();
- NavigationServer3D::get_singleton()->obstacle_set_height(obstacle, height);
- NavigationServer3D::get_singleton()->obstacle_set_radius(obstacle, radius);
- NavigationServer3D::get_singleton()->obstacle_set_vertices(obstacle, vertices);
- NavigationServer3D::get_singleton()->obstacle_set_avoidance_layers(obstacle, avoidance_layers);
- NavigationServer3D::get_singleton()->obstacle_set_use_3d_avoidance(obstacle, use_3d_avoidance);
- NavigationServer3D::get_singleton()->obstacle_set_avoidance_enabled(obstacle, avoidance_enabled);
+ obstacle = ns3d->obstacle_create();
+
+ ns3d->obstacle_set_height(obstacle, height);
+ ns3d->obstacle_set_radius(obstacle, radius);
+ ns3d->obstacle_set_vertices(obstacle, vertices);
+ ns3d->obstacle_set_avoidance_layers(obstacle, avoidance_layers);
+ ns3d->obstacle_set_use_3d_avoidance(obstacle, use_3d_avoidance);
+ ns3d->obstacle_set_avoidance_enabled(obstacle, avoidance_enabled);
#ifdef DEBUG_ENABLED
- NavigationServer3D::get_singleton()->connect("avoidance_debug_changed", callable_mp(this, &NavigationObstacle3D::_update_fake_agent_radius_debug));
- NavigationServer3D::get_singleton()->connect("avoidance_debug_changed", callable_mp(this, &NavigationObstacle3D::_update_static_obstacle_debug));
+ RenderingServer *rs = RenderingServer::get_singleton();
+
+ fake_agent_radius_debug_mesh_rid = rs->mesh_create();
+ static_obstacle_debug_mesh_rid = rs->mesh_create();
+
+ fake_agent_radius_debug_instance_rid = rs->instance_create();
+ static_obstacle_debug_instance_rid = rs->instance_create();
+
+ rs->instance_set_base(fake_agent_radius_debug_instance_rid, fake_agent_radius_debug_mesh_rid);
+ rs->instance_set_base(static_obstacle_debug_instance_rid, static_obstacle_debug_mesh_rid);
+
+ ns3d->connect("avoidance_debug_changed", callable_mp(this, &NavigationObstacle3D::_update_fake_agent_radius_debug));
+ ns3d->connect("avoidance_debug_changed", callable_mp(this, &NavigationObstacle3D::_update_static_obstacle_debug));
_update_fake_agent_radius_debug();
_update_static_obstacle_debug();
#endif // DEBUG_ENABLED
+
+#ifdef TOOLS_ENABLED
+ set_notify_transform(true);
+#endif // TOOLS_ENABLED
}
NavigationObstacle3D::~NavigationObstacle3D() {
- ERR_FAIL_NULL(NavigationServer3D::get_singleton());
+ NavigationServer3D *ns3d = NavigationServer3D::get_singleton();
+ ERR_FAIL_NULL(ns3d);
- NavigationServer3D::get_singleton()->free(obstacle);
+ ns3d->free(obstacle);
obstacle = RID();
#ifdef DEBUG_ENABLED
- NavigationServer3D::get_singleton()->disconnect("avoidance_debug_changed", callable_mp(this, &NavigationObstacle3D::_update_fake_agent_radius_debug));
- NavigationServer3D::get_singleton()->disconnect("avoidance_debug_changed", callable_mp(this, &NavigationObstacle3D::_update_static_obstacle_debug));
- if (fake_agent_radius_debug_instance.is_valid()) {
- RenderingServer::get_singleton()->free(fake_agent_radius_debug_instance);
+ ns3d->disconnect("avoidance_debug_changed", callable_mp(this, &NavigationObstacle3D::_update_fake_agent_radius_debug));
+ ns3d->disconnect("avoidance_debug_changed", callable_mp(this, &NavigationObstacle3D::_update_static_obstacle_debug));
+
+ RenderingServer *rs = RenderingServer::get_singleton();
+ ERR_FAIL_NULL(rs);
+ if (fake_agent_radius_debug_instance_rid.is_valid()) {
+ rs->free(fake_agent_radius_debug_instance_rid);
+ fake_agent_radius_debug_instance_rid = RID();
}
- if (fake_agent_radius_debug_mesh.is_valid()) {
- RenderingServer::get_singleton()->free(fake_agent_radius_debug_mesh->get_rid());
+ if (fake_agent_radius_debug_mesh_rid.is_valid()) {
+ rs->free(fake_agent_radius_debug_mesh_rid);
+ fake_agent_radius_debug_mesh_rid = RID();
}
-
- if (static_obstacle_debug_instance.is_valid()) {
- RenderingServer::get_singleton()->free(static_obstacle_debug_instance);
+ if (static_obstacle_debug_instance_rid.is_valid()) {
+ rs->free(static_obstacle_debug_instance_rid);
+ static_obstacle_debug_instance_rid = RID();
}
- if (static_obstacle_debug_mesh.is_valid()) {
- RenderingServer::get_singleton()->free(static_obstacle_debug_mesh->get_rid());
+ if (static_obstacle_debug_mesh_rid.is_valid()) {
+ rs->free(static_obstacle_debug_mesh_rid);
+ static_obstacle_debug_mesh_rid = RID();
}
#endif // DEBUG_ENABLED
}
void NavigationObstacle3D::set_vertices(const Vector<Vector3> &p_vertices) {
vertices = p_vertices;
- NavigationServer3D::get_singleton()->obstacle_set_vertices(obstacle, vertices);
+
+ const Basis basis = is_inside_tree() ? get_global_basis() : get_basis();
+ const float rotation_y = is_inside_tree() ? get_global_rotation().y : get_rotation().y;
+ const Vector3 safe_scale = basis.get_scale().abs().maxf(0.001);
+ const Transform3D safe_transform = Transform3D(Basis().scaled(safe_scale).rotated(Vector3(0.0, 1.0, 0.0), rotation_y), Vector3());
+ NavigationServer3D::get_singleton()->obstacle_set_vertices(obstacle, safe_transform.xform(vertices));
#ifdef DEBUG_ENABLED
_update_static_obstacle_debug();
+ update_gizmos();
#endif // DEBUG_ENABLED
}
@@ -272,10 +293,14 @@ void NavigationObstacle3D::set_radius(real_t p_radius) {
}
radius = p_radius;
- NavigationServer3D::get_singleton()->obstacle_set_radius(obstacle, radius);
+
+ // Prevent non-positive or non-uniform scaling of dynamic obstacle radius.
+ const Vector3 safe_scale = (is_inside_tree() ? get_global_basis() : get_basis()).get_scale().abs().maxf(0.001);
+ NavigationServer3D::get_singleton()->obstacle_set_radius(obstacle, safe_scale[safe_scale.max_axis_index()] * radius);
#ifdef DEBUG_ENABLED
_update_fake_agent_radius_debug();
+ update_gizmos();
#endif // DEBUG_ENABLED
}
@@ -286,10 +311,12 @@ void NavigationObstacle3D::set_height(real_t p_height) {
}
height = p_height;
- NavigationServer3D::get_singleton()->obstacle_set_height(obstacle, height);
+ const float scale_factor = MAX(Math::abs((is_inside_tree() ? get_global_basis() : get_basis()).get_scale().y), 0.001);
+ NavigationServer3D::get_singleton()->obstacle_set_height(obstacle, scale_factor * height);
#ifdef DEBUG_ENABLED
_update_static_obstacle_debug();
+ update_gizmos();
#endif // DEBUG_ENABLED
}
@@ -388,36 +415,63 @@ void NavigationObstacle3D::_update_position(const Vector3 p_position) {
NavigationServer3D::get_singleton()->obstacle_set_position(obstacle, p_position);
}
+void NavigationObstacle3D::_update_transform() {
+ _update_position(get_global_position());
+
+ // Prevent non-positive or non-uniform scaling of dynamic obstacle radius.
+ const Vector3 safe_scale = get_global_basis().get_scale().abs().maxf(0.001);
+ const float scaling_max_value = safe_scale[safe_scale.max_axis_index()];
+ NavigationServer3D::get_singleton()->obstacle_set_radius(obstacle, scaling_max_value * radius);
+
+ // Apply modified node transform which only takes y-axis rotation into account to vertices.
+ const Transform3D safe_transform = Transform3D(Basis().scaled(safe_scale).rotated(Vector3(0.0, 1.0, 0.0), get_global_rotation().y), Vector3());
+ NavigationServer3D::get_singleton()->obstacle_set_vertices(obstacle, safe_transform.xform(vertices));
+ NavigationServer3D::get_singleton()->obstacle_set_height(obstacle, safe_scale.y * height);
+}
+
void NavigationObstacle3D::_update_use_3d_avoidance(bool p_use_3d_avoidance) {
NavigationServer3D::get_singleton()->obstacle_set_use_3d_avoidance(obstacle, use_3d_avoidance);
_update_map(map_current);
}
#ifdef DEBUG_ENABLED
+void NavigationObstacle3D::_update_debug() {
+ RenderingServer *rs = RenderingServer::get_singleton();
+ if (is_inside_tree()) {
+ rs->instance_set_visible(fake_agent_radius_debug_instance_rid, is_visible_in_tree());
+ rs->instance_set_visible(static_obstacle_debug_instance_rid, is_visible_in_tree());
+ rs->instance_set_scenario(fake_agent_radius_debug_instance_rid, get_world_3d()->get_scenario());
+ rs->instance_set_scenario(static_obstacle_debug_instance_rid, get_world_3d()->get_scenario());
+ rs->instance_set_transform(fake_agent_radius_debug_instance_rid, Transform3D(Basis(), get_global_position()));
+ rs->instance_set_transform(static_obstacle_debug_instance_rid, Transform3D(Basis(), get_global_position()));
+ _update_fake_agent_radius_debug();
+ _update_static_obstacle_debug();
+ } else {
+ rs->mesh_clear(fake_agent_radius_debug_mesh_rid);
+ rs->mesh_clear(static_obstacle_debug_mesh_rid);
+ rs->instance_set_scenario(fake_agent_radius_debug_instance_rid, RID());
+ rs->instance_set_scenario(static_obstacle_debug_instance_rid, RID());
+ }
+}
+
void NavigationObstacle3D::_update_fake_agent_radius_debug() {
+ NavigationServer3D *ns3d = NavigationServer3D::get_singleton();
+ RenderingServer *rs = RenderingServer::get_singleton();
+
bool is_debug_enabled = false;
if (Engine::get_singleton()->is_editor_hint()) {
is_debug_enabled = true;
- } else if (NavigationServer3D::get_singleton()->get_debug_enabled() &&
- NavigationServer3D::get_singleton()->get_debug_avoidance_enabled() &&
- NavigationServer3D::get_singleton()->get_debug_navigation_avoidance_enable_obstacles_radius()) {
+ } else if (ns3d->get_debug_enabled() &&
+ ns3d->get_debug_avoidance_enabled() &&
+ ns3d->get_debug_navigation_avoidance_enable_obstacles_radius()) {
is_debug_enabled = true;
}
- if (is_debug_enabled == false) {
- if (fake_agent_radius_debug_instance.is_valid()) {
- RS::get_singleton()->instance_set_visible(fake_agent_radius_debug_instance, false);
- }
- return;
- }
+ rs->mesh_clear(fake_agent_radius_debug_mesh_rid);
- if (!fake_agent_radius_debug_instance.is_valid()) {
- fake_agent_radius_debug_instance = RenderingServer::get_singleton()->instance_create();
- }
- if (fake_agent_radius_debug_mesh.is_null()) {
- fake_agent_radius_debug_mesh.instantiate();
+ if (!is_debug_enabled) {
+ return;
}
- fake_agent_radius_debug_mesh->clear_surfaces();
Vector<Vector3> face_vertex_array;
Vector<int> face_indices_array;
@@ -472,147 +526,106 @@ void NavigationObstacle3D::_update_fake_agent_radius_debug() {
face_mesh_array[Mesh::ARRAY_VERTEX] = face_vertex_array;
face_mesh_array[Mesh::ARRAY_INDEX] = face_indices_array;
- fake_agent_radius_debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, face_mesh_array);
- Ref<StandardMaterial3D> face_material = NavigationServer3D::get_singleton()->get_debug_navigation_avoidance_obstacles_radius_material();
- fake_agent_radius_debug_mesh->surface_set_material(0, face_material);
+ rs->mesh_add_surface_from_arrays(fake_agent_radius_debug_mesh_rid, RS::PRIMITIVE_TRIANGLES, face_mesh_array);
+
+ Ref<StandardMaterial3D> face_material = ns3d->get_debug_navigation_avoidance_obstacles_radius_material();
+ rs->instance_set_surface_override_material(fake_agent_radius_debug_instance_rid, 0, face_material->get_rid());
- RS::get_singleton()->instance_set_base(fake_agent_radius_debug_instance, fake_agent_radius_debug_mesh->get_rid());
if (is_inside_tree()) {
- RS::get_singleton()->instance_set_scenario(fake_agent_radius_debug_instance, get_world_3d()->get_scenario());
- RS::get_singleton()->instance_set_visible(fake_agent_radius_debug_instance, is_visible_in_tree());
+ rs->instance_set_scenario(fake_agent_radius_debug_instance_rid, get_world_3d()->get_scenario());
+ rs->instance_set_visible(fake_agent_radius_debug_instance_rid, is_visible_in_tree());
}
}
#endif // DEBUG_ENABLED
#ifdef DEBUG_ENABLED
void NavigationObstacle3D::_update_static_obstacle_debug() {
- bool is_debug_enabled = false;
if (Engine::get_singleton()->is_editor_hint()) {
- is_debug_enabled = true;
- } else if (NavigationServer3D::get_singleton()->get_debug_enabled() &&
- NavigationServer3D::get_singleton()->get_debug_avoidance_enabled() &&
- NavigationServer3D::get_singleton()->get_debug_navigation_avoidance_enable_obstacles_static()) {
- is_debug_enabled = true;
- }
-
- if (is_debug_enabled == false) {
- if (static_obstacle_debug_instance.is_valid()) {
- RS::get_singleton()->instance_set_visible(static_obstacle_debug_instance, false);
- }
+ // Don't update inside Editor as Node3D gizmo takes care of this.
return;
}
- if (vertices.size() < 3) {
- if (static_obstacle_debug_instance.is_valid()) {
- RS::get_singleton()->instance_set_visible(static_obstacle_debug_instance, false);
- }
- return;
- }
+ NavigationServer3D *ns3d = NavigationServer3D::get_singleton();
+ RenderingServer *rs = RenderingServer::get_singleton();
- if (!static_obstacle_debug_instance.is_valid()) {
- static_obstacle_debug_instance = RenderingServer::get_singleton()->instance_create();
- }
- if (static_obstacle_debug_mesh.is_null()) {
- static_obstacle_debug_mesh.instantiate();
- }
- static_obstacle_debug_mesh->clear_surfaces();
-
- Vector<Vector2> polygon_2d_vertices;
- polygon_2d_vertices.resize(vertices.size());
- Vector2 *polygon_2d_vertices_ptr = polygon_2d_vertices.ptrw();
-
- for (int i = 0; i < vertices.size(); ++i) {
- Vector3 obstacle_vertex = vertices[i];
- Vector2 obstacle_vertex_2d = Vector2(obstacle_vertex.x, obstacle_vertex.z);
- polygon_2d_vertices_ptr[i] = obstacle_vertex_2d;
+ bool is_debug_enabled = false;
+ if (ns3d->get_debug_enabled() &&
+ ns3d->get_debug_avoidance_enabled() &&
+ ns3d->get_debug_navigation_avoidance_enable_obstacles_static()) {
+ is_debug_enabled = true;
}
- Vector<int> triangulated_polygon_2d_indices = Geometry2D::triangulate_polygon(polygon_2d_vertices);
+ rs->mesh_clear(static_obstacle_debug_mesh_rid);
- if (triangulated_polygon_2d_indices.is_empty()) {
- // failed triangulation
+ if (!is_debug_enabled) {
return;
}
- bool obstacle_pushes_inward = Geometry2D::is_polygon_clockwise(polygon_2d_vertices);
-
- Vector<Vector3> face_vertex_array;
- Vector<int> face_indices_array;
-
- face_vertex_array.resize(polygon_2d_vertices.size());
- face_indices_array.resize(triangulated_polygon_2d_indices.size());
+ const int vertex_count = vertices.size();
- Vector3 *face_vertex_array_ptr = face_vertex_array.ptrw();
- int *face_indices_array_ptr = face_indices_array.ptrw();
-
- for (int i = 0; i < triangulated_polygon_2d_indices.size(); ++i) {
- int vertex_index = triangulated_polygon_2d_indices[i];
- const Vector2 &vertex_2d = polygon_2d_vertices[vertex_index];
- Vector3 vertex_3d = Vector3(vertex_2d.x, 0.0, vertex_2d.y);
- face_vertex_array_ptr[vertex_index] = vertex_3d;
- face_indices_array_ptr[i] = vertex_index;
+ if (vertex_count < 3) {
+ if (static_obstacle_debug_instance_rid.is_valid()) {
+ rs->instance_set_visible(static_obstacle_debug_instance_rid, false);
+ }
+ return;
}
- Array face_mesh_array;
- face_mesh_array.resize(Mesh::ARRAY_MAX);
- face_mesh_array[Mesh::ARRAY_VERTEX] = face_vertex_array;
- face_mesh_array[Mesh::ARRAY_INDEX] = face_indices_array;
-
- static_obstacle_debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, face_mesh_array);
-
Vector<Vector3> edge_vertex_array;
+ edge_vertex_array.resize(vertex_count * 8);
- for (int i = 0; i < polygon_2d_vertices.size(); ++i) {
- int from_index = i - 1;
- int to_index = i;
+ Vector3 *edge_vertex_array_ptrw = edge_vertex_array.ptrw();
- if (i == 0) {
- from_index = polygon_2d_vertices.size() - 1;
- }
+ int vertex_index = 0;
- const Vector2 &vertex_2d_from = polygon_2d_vertices[from_index];
- const Vector2 &vertex_2d_to = polygon_2d_vertices[to_index];
+ for (int i = 0; i < vertex_count; i++) {
+ Vector3 point = vertices[i];
+ Vector3 next_point = vertices[(i + 1) % vertex_count];
- Vector3 vertex_3d_ground_from = Vector3(vertex_2d_from.x, 0.0, vertex_2d_from.y);
- Vector3 vertex_3d_ground_to = Vector3(vertex_2d_to.x, 0.0, vertex_2d_to.y);
+ Vector3 direction = next_point.direction_to(point);
+ Vector3 arrow_dir = direction.cross(Vector3(0.0, 1.0, 0.0));
+ Vector3 edge_middle = point + ((next_point - point) * 0.5);
- edge_vertex_array.push_back(vertex_3d_ground_from);
- edge_vertex_array.push_back(vertex_3d_ground_to);
+ edge_vertex_array_ptrw[vertex_index++] = edge_middle;
+ edge_vertex_array_ptrw[vertex_index++] = edge_middle + (arrow_dir * 0.5);
- Vector3 vertex_3d_height_from = Vector3(vertex_2d_from.x, height, vertex_2d_from.y);
- Vector3 vertex_3d_height_to = Vector3(vertex_2d_to.x, height, vertex_2d_to.y);
+ edge_vertex_array_ptrw[vertex_index++] = point;
+ edge_vertex_array_ptrw[vertex_index++] = next_point;
- edge_vertex_array.push_back(vertex_3d_height_from);
- edge_vertex_array.push_back(vertex_3d_height_to);
+ edge_vertex_array_ptrw[vertex_index++] = Vector3(point.x, height, point.z);
+ edge_vertex_array_ptrw[vertex_index++] = Vector3(next_point.x, height, next_point.z);
- edge_vertex_array.push_back(vertex_3d_ground_from);
- edge_vertex_array.push_back(vertex_3d_height_from);
+ edge_vertex_array_ptrw[vertex_index++] = point;
+ edge_vertex_array_ptrw[vertex_index++] = Vector3(point.x, height, point.z);
}
Array edge_mesh_array;
edge_mesh_array.resize(Mesh::ARRAY_MAX);
edge_mesh_array[Mesh::ARRAY_VERTEX] = edge_vertex_array;
- static_obstacle_debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, edge_mesh_array);
+ rs->mesh_add_surface_from_arrays(static_obstacle_debug_mesh_rid, RS::PRIMITIVE_LINES, edge_mesh_array);
+
+ Vector<Vector2> polygon_2d_vertices;
+ polygon_2d_vertices.resize(vertex_count);
+ for (int i = 0; i < vertex_count; i++) {
+ const Vector3 &vert = vertices[i];
+ polygon_2d_vertices.write[i] = Vector2(vert.x, vert.z);
+ }
+
+ Vector<int> triangulated_polygon_2d_indices = Geometry2D::triangulate_polygon(polygon_2d_vertices);
- Ref<StandardMaterial3D> face_material;
Ref<StandardMaterial3D> edge_material;
- if (obstacle_pushes_inward) {
- face_material = NavigationServer3D::get_singleton()->get_debug_navigation_avoidance_static_obstacle_pushin_face_material();
- edge_material = NavigationServer3D::get_singleton()->get_debug_navigation_avoidance_static_obstacle_pushin_edge_material();
+ if (triangulated_polygon_2d_indices.is_empty()) {
+ edge_material = ns3d->get_debug_navigation_avoidance_static_obstacle_pushin_edge_material();
} else {
- face_material = NavigationServer3D::get_singleton()->get_debug_navigation_avoidance_static_obstacle_pushout_face_material();
- edge_material = NavigationServer3D::get_singleton()->get_debug_navigation_avoidance_static_obstacle_pushout_edge_material();
+ edge_material = ns3d->get_debug_navigation_avoidance_static_obstacle_pushout_edge_material();
}
- static_obstacle_debug_mesh->surface_set_material(0, face_material);
- static_obstacle_debug_mesh->surface_set_material(1, edge_material);
+ rs->instance_set_surface_override_material(static_obstacle_debug_instance_rid, 0, edge_material->get_rid());
- RS::get_singleton()->instance_set_base(static_obstacle_debug_instance, static_obstacle_debug_mesh->get_rid());
if (is_inside_tree()) {
- RS::get_singleton()->instance_set_scenario(static_obstacle_debug_instance, get_world_3d()->get_scenario());
- RS::get_singleton()->instance_set_visible(static_obstacle_debug_instance, is_visible_in_tree());
+ rs->instance_set_scenario(static_obstacle_debug_instance_rid, get_world_3d()->get_scenario());
+ rs->instance_set_visible(static_obstacle_debug_instance_rid, is_visible_in_tree());
}
}
#endif // DEBUG_ENABLED
diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h
index 111abad842..25f376e68b 100644
--- a/scene/3d/navigation_obstacle_3d.h
+++ b/scene/3d/navigation_obstacle_3d.h
@@ -51,8 +51,6 @@ class NavigationObstacle3D : public Node3D {
bool use_3d_avoidance = false;
- Transform3D previous_transform;
-
Vector3 velocity;
Vector3 previous_velocity;
bool velocity_submitted = false;
@@ -61,13 +59,14 @@ class NavigationObstacle3D : public Node3D {
bool carve_navigation_mesh = false;
#ifdef DEBUG_ENABLED
- RID fake_agent_radius_debug_instance;
- Ref<ArrayMesh> fake_agent_radius_debug_mesh;
+ RID fake_agent_radius_debug_instance_rid;
+ RID fake_agent_radius_debug_mesh_rid;
- RID static_obstacle_debug_instance;
- Ref<ArrayMesh> static_obstacle_debug_mesh;
+ RID static_obstacle_debug_instance_rid;
+ RID static_obstacle_debug_mesh_rid;
private:
+ void _update_debug();
void _update_fake_agent_radius_debug();
void _update_static_obstacle_debug();
#endif // DEBUG_ENABLED
@@ -122,6 +121,7 @@ public:
private:
void _update_map(RID p_map);
void _update_position(const Vector3 p_position);
+ void _update_transform();
void _update_use_3d_avoidance(bool p_use_3d_avoidance);
};
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index 85de85a9a6..cd77a32455 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -841,10 +841,10 @@ void Node3D::reparent(Node *p_parent, bool p_keep_global_transform) {
ERR_THREAD_GUARD;
if (p_keep_global_transform) {
Transform3D temp = get_global_transform();
- Node::reparent(p_parent);
+ Node::reparent(p_parent, p_keep_global_transform);
set_global_transform(temp);
} else {
- Node::reparent(p_parent);
+ Node::reparent(p_parent, p_keep_global_transform);
}
}
diff --git a/scene/3d/physics/collision_shape_3d.cpp b/scene/3d/physics/collision_shape_3d.cpp
index 304fa74b06..362c61026b 100644
--- a/scene/3d/physics/collision_shape_3d.cpp
+++ b/scene/3d/physics/collision_shape_3d.cpp
@@ -81,12 +81,19 @@ void CollisionShape3D::_update_in_shape_owner(bool p_xform_only) {
void CollisionShape3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_PARENTED: {
+#ifdef DEBUG_ENABLED
+ if (debug_color == get_placeholder_default_color()) {
+ debug_color = SceneTree::get_singleton()->get_debug_collisions_color();
+ }
+#endif // DEBUG_ENABLED
+
collision_object = Object::cast_to<CollisionObject3D>(get_parent());
if (collision_object) {
owner_id = collision_object->create_shape_owner(this);
if (shape.is_valid()) {
collision_object->shape_owner_add_shape(owner_id, shape);
}
+
_update_in_shape_owner();
}
} break;
@@ -166,11 +173,26 @@ void CollisionShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_shape"), &CollisionShape3D::get_shape);
ClassDB::bind_method(D_METHOD("set_disabled", "enable"), &CollisionShape3D::set_disabled);
ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionShape3D::is_disabled);
+
ClassDB::bind_method(D_METHOD("make_convex_from_siblings"), &CollisionShape3D::make_convex_from_siblings);
ClassDB::set_method_flags("CollisionShape3D", "make_convex_from_siblings", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape3D"), "set_shape", "get_shape");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
+
+#ifdef DEBUG_ENABLED
+ ClassDB::bind_method(D_METHOD("set_debug_color", "color"), &CollisionShape3D::set_debug_color);
+ ClassDB::bind_method(D_METHOD("get_debug_color"), &CollisionShape3D::get_debug_color);
+
+ ClassDB::bind_method(D_METHOD("set_enable_debug_fill", "enable"), &CollisionShape3D::set_debug_fill_enabled);
+ ClassDB::bind_method(D_METHOD("get_enable_debug_fill"), &CollisionShape3D::get_debug_fill_enabled);
+
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "debug_color"), "set_debug_color", "get_debug_color");
+ // Default value depends on a project setting, override for doc generation purposes.
+ ADD_PROPERTY_DEFAULT("debug_color", get_placeholder_default_color());
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_fill"), "set_enable_debug_fill", "get_enable_debug_fill");
+#endif // DEBUG_ENABLED
}
void CollisionShape3D::set_shape(const Ref<Shape3D> &p_shape) {
@@ -178,11 +200,27 @@ void CollisionShape3D::set_shape(const Ref<Shape3D> &p_shape) {
return;
}
if (shape.is_valid()) {
+ shape->disconnect_changed(callable_mp(this, &CollisionShape3D::shape_changed));
shape->disconnect_changed(callable_mp((Node3D *)this, &Node3D::update_gizmos));
}
shape = p_shape;
if (shape.is_valid()) {
+#ifdef DEBUG_ENABLED
+ if (shape->get_debug_color() != get_placeholder_default_color()) {
+ set_debug_color(shape->get_debug_color());
+ set_debug_fill_enabled(shape->get_debug_fill());
+ } else if (get_debug_color() != get_placeholder_default_color()) {
+ shape->set_debug_color(debug_color);
+ shape->set_debug_fill(debug_fill);
+ } else {
+ set_debug_color(SceneTree::get_singleton()->get_debug_collisions_color());
+ shape->set_debug_color(SceneTree::get_singleton()->get_debug_collisions_color());
+ shape->set_debug_fill(debug_fill);
+ }
+#endif // DEBUG_ENABLED
+
shape->connect_changed(callable_mp((Node3D *)this, &Node3D::update_gizmos));
+ shape->connect_changed(callable_mp(this, &CollisionShape3D::shape_changed));
}
update_gizmos();
if (collision_object) {
@@ -215,6 +253,66 @@ bool CollisionShape3D::is_disabled() const {
return disabled;
}
+#ifdef DEBUG_ENABLED
+void CollisionShape3D::set_debug_color(const Color &p_color) {
+ if (p_color == get_placeholder_default_color()) {
+ debug_color = SceneTree::get_singleton()->get_debug_collisions_color();
+ } else if (debug_color != p_color) {
+ debug_color = p_color;
+
+ if (shape.is_valid()) {
+ shape->set_debug_color(p_color);
+ }
+ }
+}
+
+Color CollisionShape3D::get_debug_color() const {
+ return debug_color;
+}
+
+void CollisionShape3D::set_debug_fill_enabled(bool p_enable) {
+ if (debug_fill == p_enable) {
+ return;
+ }
+
+ debug_fill = p_enable;
+
+ if (shape.is_valid()) {
+ shape->set_debug_fill(p_enable);
+ }
+}
+
+bool CollisionShape3D::get_debug_fill_enabled() const {
+ return debug_fill;
+}
+
+bool CollisionShape3D::_property_can_revert(const StringName &p_name) const {
+ if (p_name == "debug_color") {
+ return true;
+ }
+ return false;
+}
+
+bool CollisionShape3D::_property_get_revert(const StringName &p_name, Variant &r_property) const {
+ if (p_name == "debug_color") {
+ r_property = SceneTree::get_singleton()->get_debug_collisions_color();
+ return true;
+ }
+ return false;
+}
+#endif // DEBUG_ENABLED
+
+void CollisionShape3D::shape_changed() {
+#ifdef DEBUG_ENABLED
+ if (shape->get_debug_color() != debug_color) {
+ set_debug_color(shape->get_debug_color());
+ }
+ if (shape->get_debug_fill() != debug_fill) {
+ set_debug_fill_enabled(shape->get_debug_fill());
+ }
+#endif // DEBUG_ENABLED
+}
+
CollisionShape3D::CollisionShape3D() {
//indicator = RenderingServer::get_singleton()->mesh_create();
set_notify_local_transform(true);
diff --git a/scene/3d/physics/collision_shape_3d.h b/scene/3d/physics/collision_shape_3d.h
index 15f6ef73cb..0eaecb9f61 100644
--- a/scene/3d/physics/collision_shape_3d.h
+++ b/scene/3d/physics/collision_shape_3d.h
@@ -43,6 +43,13 @@ class CollisionShape3D : public Node3D {
uint32_t owner_id = 0;
CollisionObject3D *collision_object = nullptr;
+#ifdef DEBUG_ENABLED
+ Color debug_color = get_placeholder_default_color();
+ bool debug_fill = true;
+
+ static const Color get_placeholder_default_color() { return Color(0.0, 0.0, 0.0, 0.0); }
+#endif // DEBUG_ENABLED
+
#ifndef DISABLE_DEPRECATED
void resource_changed(Ref<Resource> res);
#endif
@@ -55,6 +62,13 @@ protected:
void _notification(int p_what);
static void _bind_methods();
+#ifdef DEBUG_ENABLED
+ bool _property_can_revert(const StringName &p_name) const;
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
+#endif // DEBUG_ENABLED
+
+ void shape_changed();
+
public:
void make_convex_from_siblings();
@@ -64,6 +78,14 @@ public:
void set_disabled(bool p_disabled);
bool is_disabled() const;
+#ifdef DEBUG_ENABLED
+ void set_debug_color(const Color &p_color);
+ Color get_debug_color() const;
+
+ void set_debug_fill_enabled(bool p_enable);
+ bool get_debug_fill_enabled() const;
+#endif // DEBUG_ENABLED
+
PackedStringArray get_configuration_warnings() const override;
CollisionShape3D();
diff --git a/scene/3d/physics/rigid_body_3d.cpp b/scene/3d/physics/rigid_body_3d.cpp
index 275e8cd7a9..6c8cea1ac3 100644
--- a/scene/3d/physics/rigid_body_3d.cpp
+++ b/scene/3d/physics/rigid_body_3d.cpp
@@ -659,7 +659,7 @@ void RigidBody3D::_reload_physics_characteristics() {
}
PackedStringArray RigidBody3D::get_configuration_warnings() const {
- PackedStringArray warnings = CollisionObject3D::get_configuration_warnings();
+ PackedStringArray warnings = PhysicsBody3D::get_configuration_warnings();
Vector3 scale = get_transform().get_basis().get_scale();
if (ABS(scale.x - 1.0) > 0.05 || ABS(scale.y - 1.0) > 0.05 || ABS(scale.z - 1.0) > 0.05) {
diff --git a/scene/3d/retarget_modifier_3d.cpp b/scene/3d/retarget_modifier_3d.cpp
new file mode 100644
index 0000000000..90cc316a56
--- /dev/null
+++ b/scene/3d/retarget_modifier_3d.cpp
@@ -0,0 +1,441 @@
+/**************************************************************************/
+/* retarget_modifier_3d.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "retarget_modifier_3d.h"
+
+PackedStringArray RetargetModifier3D::get_configuration_warnings() const {
+ PackedStringArray warnings = SkeletonModifier3D::get_configuration_warnings();
+ if (child_skeletons.is_empty()) {
+ warnings.push_back(RTR("There is no child Skeleton3D!"));
+ }
+ return warnings;
+}
+
+/// Caching
+
+void RetargetModifier3D::_profile_changed(Ref<SkeletonProfile> p_old, Ref<SkeletonProfile> p_new) {
+ if (p_old.is_valid() && p_old->is_connected(SNAME("profile_updated"), callable_mp(this, &RetargetModifier3D::cache_rests_with_reset))) {
+ p_old->disconnect(SNAME("profile_updated"), callable_mp(this, &RetargetModifier3D::cache_rests_with_reset));
+ }
+ profile = p_new;
+ if (p_new.is_valid() && !p_new->is_connected(SNAME("profile_updated"), callable_mp(this, &RetargetModifier3D::cache_rests_with_reset))) {
+ p_new->connect(SNAME("profile_updated"), callable_mp(this, &RetargetModifier3D::cache_rests_with_reset));
+ }
+ cache_rests_with_reset();
+}
+
+void RetargetModifier3D::_skeleton_changed(Skeleton3D *p_old, Skeleton3D *p_new) {
+ if (p_old && p_old->is_connected(SNAME("rest_updated"), callable_mp(this, &RetargetModifier3D::cache_rests))) {
+ p_old->disconnect(SNAME("rest_updated"), callable_mp(this, &RetargetModifier3D::cache_rests));
+ }
+ if (p_new && !p_new->is_connected(SNAME("rest_updated"), callable_mp(this, &RetargetModifier3D::cache_rests))) {
+ p_new->connect(SNAME("rest_updated"), callable_mp(this, &RetargetModifier3D::cache_rests));
+ }
+ cache_rests();
+}
+
+void RetargetModifier3D::cache_rests_with_reset() {
+ _reset_child_skeleton_poses();
+ cache_rests();
+}
+
+void RetargetModifier3D::cache_rests() {
+ source_bone_ids.clear();
+
+ Skeleton3D *source_skeleton = get_skeleton();
+ if (profile.is_null() || !source_skeleton) {
+ return;
+ }
+
+ PackedStringArray bone_names = profile->get_bone_names();
+ for (const String &E : bone_names) {
+ source_bone_ids.push_back(source_skeleton->find_bone(E));
+ }
+
+ for (int i = 0; i < child_skeletons.size(); i++) {
+ _update_child_skeleton_rests(i);
+ }
+}
+
+Vector<RetargetModifier3D::RetargetBoneInfo> RetargetModifier3D::cache_bone_global_rests(Skeleton3D *p_skeleton) {
+ // Retarget global pose in model space:
+ // tgt_global_pose.basis = src_global_pose.basis * src_rest.basis.inv * src_parent_global_rest.basis.inv * tgt_parent_global_rest.basis * tgt_rest.basis
+ // tgt_global_pose.origin = src_global_pose.origin
+ Skeleton3D *source_skeleton = get_skeleton();
+ Vector<RetargetBoneInfo> bone_rests;
+ if (profile.is_null() || !source_skeleton) {
+ return bone_rests;
+ }
+ PackedStringArray bone_names = profile->get_bone_names();
+ for (const String &E : bone_names) {
+ RetargetBoneInfo rbi;
+ int source_bone_id = source_skeleton->find_bone(E);
+ if (source_bone_id >= 0) {
+ Transform3D parent_global_rest;
+ int bone_parent = source_skeleton->get_bone_parent(source_bone_id);
+ if (bone_parent >= 0) {
+ parent_global_rest = source_skeleton->get_bone_global_rest(bone_parent);
+ }
+ rbi.post_basis = source_skeleton->get_bone_rest(source_bone_id).basis.inverse() * parent_global_rest.basis.inverse();
+ }
+ int target_bone_id = p_skeleton->find_bone(E);
+ rbi.bone_id = target_bone_id;
+ if (target_bone_id >= 0) {
+ Transform3D parent_global_rest;
+ int bone_parent = p_skeleton->get_bone_parent(target_bone_id);
+ if (bone_parent >= 0) {
+ parent_global_rest = p_skeleton->get_bone_global_rest(bone_parent);
+ }
+ rbi.post_basis = rbi.post_basis * parent_global_rest.basis * p_skeleton->get_bone_rest(target_bone_id).basis;
+ }
+ bone_rests.push_back(rbi);
+ }
+ return bone_rests;
+}
+
+Vector<RetargetModifier3D::RetargetBoneInfo> RetargetModifier3D::cache_bone_rests(Skeleton3D *p_skeleton) {
+ // Retarget pose in model space:
+ // tgt_pose.basis = tgt_parent_global_rest.basis.inv * src_parent_global_rest.basis * src_pose.basis * src_rest.basis.inv * src_parent_global_rest.basis.inv * tgt_parent_global_rest.basis * tgt_rest.basis
+ // tgt_pose.origin = tgt_parent_global_rest.basis.inv.xform(src_parent_global_rest.basis.xform(src_pose.origin - src_rest.origin)) + tgt_rest.origin
+ Skeleton3D *source_skeleton = get_skeleton();
+ Vector<RetargetBoneInfo> bone_rests;
+ if (profile.is_null() || !source_skeleton) {
+ return bone_rests;
+ }
+ PackedStringArray bone_names = profile->get_bone_names();
+ for (const String &E : bone_names) {
+ RetargetBoneInfo rbi;
+ int source_bone_id = source_skeleton->find_bone(E);
+ if (source_bone_id >= 0) {
+ Transform3D parent_global_rest;
+ int bone_parent = source_skeleton->get_bone_parent(source_bone_id);
+ if (bone_parent >= 0) {
+ parent_global_rest = source_skeleton->get_bone_global_rest(bone_parent);
+ }
+ rbi.pre_basis = parent_global_rest.basis;
+ rbi.post_basis = source_skeleton->get_bone_rest(source_bone_id).basis.inverse() * parent_global_rest.basis.inverse();
+ }
+
+ int target_bone_id = p_skeleton->find_bone(E);
+ rbi.bone_id = target_bone_id;
+ if (target_bone_id >= 0) {
+ Transform3D parent_global_rest;
+ int bone_parent = p_skeleton->get_bone_parent(target_bone_id);
+ if (bone_parent >= 0) {
+ parent_global_rest = p_skeleton->get_bone_global_rest(bone_parent);
+ }
+ rbi.pre_basis = parent_global_rest.basis.inverse() * rbi.pre_basis;
+ rbi.post_basis = rbi.post_basis * parent_global_rest.basis * p_skeleton->get_bone_rest(target_bone_id).basis;
+ }
+ bone_rests.push_back(rbi);
+ }
+ return bone_rests;
+}
+
+void RetargetModifier3D::_update_child_skeleton_rests(int p_child_skeleton_idx) {
+ ERR_FAIL_INDEX(p_child_skeleton_idx, child_skeletons.size());
+ Skeleton3D *c = Object::cast_to<Skeleton3D>(ObjectDB::get_instance(child_skeletons[p_child_skeleton_idx].skeleton_id));
+ if (!c) {
+ return;
+ }
+ if (use_global_pose) {
+ child_skeletons.write[p_child_skeleton_idx].humanoid_bone_rests = cache_bone_global_rests(c);
+ } else {
+ child_skeletons.write[p_child_skeleton_idx].humanoid_bone_rests = cache_bone_rests(c);
+ }
+}
+
+void RetargetModifier3D::_update_child_skeletons() {
+ _reset_child_skeletons();
+
+ for (int i = 0; i < get_child_count(); i++) {
+ RetargetInfo ri;
+ Skeleton3D *c = Object::cast_to<Skeleton3D>(get_child(i));
+ if (c) {
+ int id = child_skeletons.size();
+ ri.skeleton_id = c->get_instance_id();
+ child_skeletons.push_back(ri);
+ c->connect(SNAME("rest_updated"), callable_mp(this, &RetargetModifier3D::_update_child_skeleton_rests).bind(id));
+ }
+ }
+
+ cache_rests();
+ update_configuration_warnings();
+}
+
+void RetargetModifier3D::_reset_child_skeleton_poses() {
+ for (const RetargetInfo &E : child_skeletons) {
+ Skeleton3D *c = Object::cast_to<Skeleton3D>(ObjectDB::get_instance(E.skeleton_id));
+ if (!c) {
+ continue;
+ }
+ if (c->is_connected(SNAME("rest_updated"), callable_mp(this, &RetargetModifier3D::_update_child_skeleton_rests))) {
+ c->disconnect(SNAME("rest_updated"), callable_mp(this, &RetargetModifier3D::_update_child_skeleton_rests));
+ }
+ for (const RetargetBoneInfo &F : E.humanoid_bone_rests) {
+ if (F.bone_id < 0) {
+ continue;
+ }
+ c->reset_bone_pose(F.bone_id);
+ }
+ }
+}
+
+void RetargetModifier3D::_reset_child_skeletons() {
+ _reset_child_skeleton_poses();
+ child_skeletons.clear();
+}
+
+/// General functions
+
+void RetargetModifier3D::add_child_notify(Node *p_child) {
+ if (Object::cast_to<Skeleton3D>(p_child)) {
+ _update_child_skeletons();
+ }
+}
+
+void RetargetModifier3D::move_child_notify(Node *p_child) {
+ if (Object::cast_to<Skeleton3D>(p_child)) {
+ _update_child_skeletons();
+ }
+}
+
+void RetargetModifier3D::remove_child_notify(Node *p_child) {
+ if (Object::cast_to<Skeleton3D>(p_child)) {
+ // Reset after process.
+ callable_mp(this, &RetargetModifier3D::_update_child_skeletons).call_deferred();
+ }
+}
+
+void RetargetModifier3D::_validate_property(PropertyInfo &p_property) const {
+ if (use_global_pose) {
+ if (p_property.name == "position_enabled" || p_property.name == "rotation_enabled" || p_property.name == "scale_enabled") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+ }
+}
+
+void RetargetModifier3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_profile", "profile"), &RetargetModifier3D::set_profile);
+ ClassDB::bind_method(D_METHOD("get_profile"), &RetargetModifier3D::get_profile);
+ ClassDB::bind_method(D_METHOD("set_use_global_pose", "use_global_pose"), &RetargetModifier3D::set_use_global_pose);
+ ClassDB::bind_method(D_METHOD("is_using_global_pose"), &RetargetModifier3D::is_using_global_pose);
+ ClassDB::bind_method(D_METHOD("set_position_enabled", "enabled"), &RetargetModifier3D::set_position_enabled);
+ ClassDB::bind_method(D_METHOD("is_position_enabled"), &RetargetModifier3D::is_position_enabled);
+ ClassDB::bind_method(D_METHOD("set_rotation_enabled", "enabled"), &RetargetModifier3D::set_rotation_enabled);
+ ClassDB::bind_method(D_METHOD("is_rotation_enabled"), &RetargetModifier3D::is_rotation_enabled);
+ ClassDB::bind_method(D_METHOD("set_scale_enabled", "enabled"), &RetargetModifier3D::set_scale_enabled);
+ ClassDB::bind_method(D_METHOD("is_scale_enabled"), &RetargetModifier3D::is_scale_enabled);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "profile", PROPERTY_HINT_RESOURCE_TYPE, "SkeletonProfile"), "set_profile", "get_profile");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_global_pose"), "set_use_global_pose", "is_using_global_pose");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "position_enabled"), "set_position_enabled", "is_position_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotation_enabled"), "set_rotation_enabled", "is_rotation_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scale_enabled"), "set_scale_enabled", "is_scale_enabled");
+}
+
+void RetargetModifier3D::_set_active(bool p_active) {
+ if (!p_active) {
+ _reset_child_skeleton_poses();
+ }
+}
+
+void RetargetModifier3D::_retarget_global_pose() {
+ Skeleton3D *source_skeleton = get_skeleton();
+ if (profile.is_null() || !source_skeleton) {
+ return;
+ }
+
+ LocalVector<Transform3D> source_poses;
+ if (influence < 1.0) {
+ for (int source_bone_id : source_bone_ids) {
+ source_poses.push_back(source_bone_id < 0 ? Transform3D() : source_skeleton->get_bone_global_rest(source_bone_id).interpolate_with(source_skeleton->get_bone_global_pose(source_bone_id), influence));
+ }
+ } else {
+ for (int source_bone_id : source_bone_ids) {
+ source_poses.push_back(source_bone_id < 0 ? Transform3D() : source_skeleton->get_bone_global_pose(source_bone_id));
+ }
+ }
+
+ for (const RetargetInfo &E : child_skeletons) {
+ Skeleton3D *target_skeleton = Object::cast_to<Skeleton3D>(ObjectDB::get_instance(E.skeleton_id));
+ if (!target_skeleton) {
+ continue;
+ }
+ for (int i = 0; i < source_bone_ids.size(); i++) {
+ int target_bone_id = E.humanoid_bone_rests[i].bone_id;
+ if (target_bone_id < 0) {
+ continue;
+ }
+ Transform3D retarget_pose = source_poses[i];
+ retarget_pose.basis = retarget_pose.basis * E.humanoid_bone_rests[i].post_basis;
+ target_skeleton->set_bone_global_pose(target_bone_id, retarget_pose);
+ }
+ }
+}
+
+void RetargetModifier3D::_retarget_pose() {
+ Skeleton3D *source_skeleton = get_skeleton();
+ if (profile.is_null() || !source_skeleton) {
+ return;
+ }
+
+ LocalVector<Transform3D> source_poses;
+ if (influence < 1.0) {
+ for (int source_bone_id : source_bone_ids) {
+ source_poses.push_back(source_bone_id < 0 ? Transform3D() : source_skeleton->get_bone_rest(source_bone_id).interpolate_with(source_skeleton->get_bone_pose(source_bone_id), influence));
+ }
+ } else {
+ for (int source_bone_id : source_bone_ids) {
+ source_poses.push_back(source_bone_id < 0 ? Transform3D() : source_skeleton->get_bone_pose(source_bone_id));
+ }
+ }
+
+ for (const RetargetInfo &E : child_skeletons) {
+ Skeleton3D *target_skeleton = Object::cast_to<Skeleton3D>(ObjectDB::get_instance(E.skeleton_id));
+ if (!target_skeleton) {
+ continue;
+ }
+ float motion_scale_ratio = target_skeleton->get_motion_scale() / source_skeleton->get_motion_scale();
+ for (int i = 0; i < source_bone_ids.size(); i++) {
+ int target_bone_id = E.humanoid_bone_rests[i].bone_id;
+ if (target_bone_id < 0) {
+ continue;
+ }
+ int source_bone_id = source_bone_ids[i];
+ if (source_bone_id < 0) {
+ continue;
+ }
+
+ Transform3D extracted_transform = source_poses[i];
+ extracted_transform.basis = E.humanoid_bone_rests[i].pre_basis * extracted_transform.basis * E.humanoid_bone_rests[i].post_basis;
+ extracted_transform.origin = E.humanoid_bone_rests[i].pre_basis.xform((extracted_transform.origin - source_skeleton->get_bone_rest(source_bone_id).origin) * motion_scale_ratio) + target_skeleton->get_bone_rest(target_bone_id).origin;
+
+ Transform3D retarget_pose = target_skeleton->get_bone_pose(target_bone_id);
+ if (enable_position) {
+ retarget_pose.origin = extracted_transform.origin;
+ }
+ if (enable_rotation) {
+ retarget_pose.basis = extracted_transform.basis.get_rotation_quaternion();
+ }
+ if (enable_scale) {
+ retarget_pose.basis.scale_local(extracted_transform.basis.get_scale());
+ }
+ target_skeleton->set_bone_pose(target_bone_id, retarget_pose);
+ }
+ }
+}
+
+void RetargetModifier3D::_process_modification() {
+ if (use_global_pose) {
+ _retarget_global_pose();
+ } else {
+ _retarget_pose();
+ }
+}
+
+void RetargetModifier3D::set_profile(Ref<SkeletonProfile> p_profile) {
+ if (profile == p_profile) {
+ return;
+ }
+ _profile_changed(profile, p_profile);
+}
+
+Ref<SkeletonProfile> RetargetModifier3D::get_profile() const {
+ return profile;
+}
+
+void RetargetModifier3D::set_use_global_pose(bool p_use_global_pose) {
+ if (use_global_pose == p_use_global_pose) {
+ return;
+ }
+
+ use_global_pose = p_use_global_pose;
+ cache_rests_with_reset();
+
+ notify_property_list_changed();
+}
+
+bool RetargetModifier3D::is_using_global_pose() const {
+ return use_global_pose;
+}
+
+void RetargetModifier3D::set_position_enabled(bool p_enabled) {
+ if (enable_position != p_enabled) {
+ _reset_child_skeleton_poses();
+ }
+ enable_position = p_enabled;
+}
+
+bool RetargetModifier3D::is_position_enabled() const {
+ return enable_position;
+}
+
+void RetargetModifier3D::set_rotation_enabled(bool p_enabled) {
+ if (enable_rotation != p_enabled) {
+ _reset_child_skeleton_poses();
+ }
+ enable_rotation = p_enabled;
+}
+
+bool RetargetModifier3D::is_rotation_enabled() const {
+ return enable_rotation;
+}
+
+void RetargetModifier3D::set_scale_enabled(bool p_enabled) {
+ if (enable_scale != p_enabled) {
+ _reset_child_skeleton_poses();
+ }
+ enable_scale = p_enabled;
+}
+
+bool RetargetModifier3D::is_scale_enabled() const {
+ return enable_scale;
+}
+
+void RetargetModifier3D::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ _update_child_skeletons();
+ } break;
+ case NOTIFICATION_EDITOR_PRE_SAVE: {
+ _reset_child_skeleton_poses();
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ _reset_child_skeletons();
+ } break;
+ }
+}
+
+RetargetModifier3D::RetargetModifier3D() {
+}
+
+RetargetModifier3D::~RetargetModifier3D() {
+}
diff --git a/scene/3d/retarget_modifier_3d.h b/scene/3d/retarget_modifier_3d.h
new file mode 100644
index 0000000000..75112d74bf
--- /dev/null
+++ b/scene/3d/retarget_modifier_3d.h
@@ -0,0 +1,110 @@
+/**************************************************************************/
+/* retarget_modifier_3d.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef RETARGET_MODIFIER_3D_H
+#define RETARGET_MODIFIER_3D_H
+
+#include "scene/3d/skeleton_modifier_3d.h"
+#include "scene/resources/skeleton_profile.h"
+
+class RetargetModifier3D : public SkeletonModifier3D {
+ GDCLASS(RetargetModifier3D, SkeletonModifier3D);
+
+ Ref<SkeletonProfile> profile;
+
+ bool use_global_pose = false;
+ bool enable_position = true;
+ bool enable_rotation = true;
+ bool enable_scale = true;
+
+ struct RetargetBoneInfo {
+ int bone_id = -1;
+ Basis pre_basis;
+ Basis post_basis;
+ };
+
+ struct RetargetInfo {
+ ObjectID skeleton_id;
+ Vector<RetargetBoneInfo> humanoid_bone_rests;
+ };
+
+ Vector<RetargetInfo> child_skeletons;
+ Vector<int> source_bone_ids;
+
+ void _update_child_skeleton_rests(int p_child_skeleton_idx);
+ void _update_child_skeletons();
+ void _reset_child_skeleton_poses();
+ void _reset_child_skeletons();
+
+ void cache_rests_with_reset();
+ void cache_rests();
+ Vector<RetargetBoneInfo> cache_bone_global_rests(Skeleton3D *p_skeleton);
+ Vector<RetargetBoneInfo> cache_bone_rests(Skeleton3D *p_skeleton);
+ Vector<RetargetBoneInfo> get_humanoid_bone_rests(Skeleton3D *p_skeleton);
+
+ void _retarget_global_pose();
+ void _retarget_pose();
+
+protected:
+ virtual void _skeleton_changed(Skeleton3D *p_old, Skeleton3D *p_new) override;
+ void _profile_changed(Ref<SkeletonProfile> p_old, Ref<SkeletonProfile> p_new);
+
+ void _validate_property(PropertyInfo &p_property) const;
+
+ static void _bind_methods();
+ virtual void _notification(int p_what);
+
+ virtual void add_child_notify(Node *p_child) override;
+ virtual void move_child_notify(Node *p_child) override;
+ virtual void remove_child_notify(Node *p_child) override;
+
+ virtual void _set_active(bool p_active) override;
+ virtual void _process_modification() override;
+
+public:
+ virtual PackedStringArray get_configuration_warnings() const override;
+
+ void set_use_global_pose(bool p_use_global_pose);
+ bool is_using_global_pose() const;
+ void set_position_enabled(bool p_enabled);
+ bool is_position_enabled() const;
+ void set_rotation_enabled(bool p_enabled);
+ bool is_rotation_enabled() const;
+ void set_scale_enabled(bool p_enabled);
+ bool is_scale_enabled() const;
+
+ void set_profile(Ref<SkeletonProfile> p_profile);
+ Ref<SkeletonProfile> get_profile() const;
+
+ RetargetModifier3D();
+ virtual ~RetargetModifier3D();
+};
+
+#endif // RETARGET_MODIFIER_3D_H
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index abece303d1..08bd60034b 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -1032,6 +1032,10 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
return skin_ref;
}
+void Skeleton3D::force_update_deferred() {
+ _make_dirty();
+}
+
void Skeleton3D::force_update_all_dirty_bones() {
if (!dirty) {
return;
@@ -1044,7 +1048,12 @@ void Skeleton3D::force_update_all_bone_transforms() {
for (int i = 0; i < parentless_bones.size(); i++) {
force_update_bone_children_transforms(parentless_bones[i]);
}
- rest_dirty = false;
+ if (rest_dirty) {
+ rest_dirty = false;
+ emit_signal(SNAME("rest_updated"));
+ } else {
+ rest_dirty = false;
+ }
dirty = false;
if (updating) {
return;
@@ -1254,6 +1263,7 @@ void Skeleton3D::_bind_methods() {
ADD_GROUP("Modifier", "modifier_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "modifier_callback_mode_process", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_modifier_callback_mode_process", "get_modifier_callback_mode_process");
+ ADD_SIGNAL(MethodInfo("rest_updated"));
ADD_SIGNAL(MethodInfo("pose_updated"));
ADD_SIGNAL(MethodInfo("skeleton_updated"));
ADD_SIGNAL(MethodInfo("bone_enabled_changed", PropertyInfo(Variant::INT, "bone_idx")));
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
index 90902f71e2..c224a79550 100644
--- a/scene/3d/skeleton_3d.h
+++ b/scene/3d/skeleton_3d.h
@@ -222,6 +222,7 @@ public:
// Skeleton creation API
uint64_t get_version() const;
int add_bone(const String &p_name);
+ void remove_bone(int p_bone);
int find_bone(const String &p_name) const;
String get_bone_name(int p_bone) const;
void set_bone_name(int p_bone, const String &p_name);
@@ -284,6 +285,7 @@ public:
void force_update_all_dirty_bones();
void force_update_all_bone_transforms();
void force_update_bone_children_transforms(int bone_idx);
+ void force_update_deferred();
void set_modifier_callback_mode_process(ModifierCallbackModeProcess p_mode);
ModifierCallbackModeProcess get_modifier_callback_mode_process() const;
diff --git a/scene/3d/skeleton_modifier_3d.cpp b/scene/3d/skeleton_modifier_3d.cpp
index d5c603112e..e8a8e517a2 100644
--- a/scene/3d/skeleton_modifier_3d.cpp
+++ b/scene/3d/skeleton_modifier_3d.cpp
@@ -75,6 +75,17 @@ void SkeletonModifier3D::_skeleton_changed(Skeleton3D *p_old, Skeleton3D *p_new)
//
}
+void SkeletonModifier3D::_force_update_skeleton_skin() {
+ if (!is_inside_tree()) {
+ return;
+ }
+ Skeleton3D *skeleton = get_skeleton();
+ if (!skeleton) {
+ return;
+ }
+ skeleton->force_update_deferred();
+}
+
/* Process */
void SkeletonModifier3D::set_active(bool p_active) {
@@ -83,6 +94,7 @@ void SkeletonModifier3D::set_active(bool p_active) {
}
active = p_active;
_set_active(active);
+ _force_update_skeleton_skin();
}
bool SkeletonModifier3D::is_active() const {
@@ -119,6 +131,10 @@ void SkeletonModifier3D::_notification(int p_what) {
case NOTIFICATION_PARENTED: {
_update_skeleton();
} break;
+ case NOTIFICATION_EXIT_TREE:
+ case NOTIFICATION_UNPARENTED: {
+ _force_update_skeleton_skin();
+ } break;
}
}
diff --git a/scene/3d/skeleton_modifier_3d.h b/scene/3d/skeleton_modifier_3d.h
index d00a1e94a9..728b000ff5 100644
--- a/scene/3d/skeleton_modifier_3d.h
+++ b/scene/3d/skeleton_modifier_3d.h
@@ -50,6 +50,7 @@ protected:
void _update_skeleton();
void _update_skeleton_path();
+ void _force_update_skeleton_skin();
virtual void _skeleton_changed(Skeleton3D *p_old, Skeleton3D *p_new);
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index a59754c8cc..2c7a004dd0 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -454,14 +454,48 @@ AABB GeometryInstance3D::get_custom_aabb() const {
return custom_aabb;
}
+void GeometryInstance3D::set_lightmap_texel_scale(float p_scale) {
+ lightmap_texel_scale = p_scale;
+}
+
+float GeometryInstance3D::get_lightmap_texel_scale() const {
+ return lightmap_texel_scale;
+}
+
+#ifndef DISABLE_DEPRECATED
void GeometryInstance3D::set_lightmap_scale(LightmapScale p_scale) {
ERR_FAIL_INDEX(p_scale, LIGHTMAP_SCALE_MAX);
- lightmap_scale = p_scale;
+ switch (p_scale) {
+ case GeometryInstance3D::LIGHTMAP_SCALE_1X:
+ lightmap_texel_scale = 1.0f;
+ break;
+ case GeometryInstance3D::LIGHTMAP_SCALE_2X:
+ lightmap_texel_scale = 2.0f;
+ break;
+ case GeometryInstance3D::LIGHTMAP_SCALE_4X:
+ lightmap_texel_scale = 4.0f;
+ break;
+ case GeometryInstance3D::LIGHTMAP_SCALE_8X:
+ lightmap_texel_scale = 8.0f;
+ break;
+ case GeometryInstance3D::LIGHTMAP_SCALE_MAX:
+ break; // Can't happen, but silences warning.
+ }
}
GeometryInstance3D::LightmapScale GeometryInstance3D::get_lightmap_scale() const {
- return lightmap_scale;
+ // Return closest approximation.
+ if (lightmap_texel_scale < 1.5f) {
+ return GeometryInstance3D::LIGHTMAP_SCALE_1X;
+ } else if (lightmap_texel_scale < 3.0f) {
+ return GeometryInstance3D::LIGHTMAP_SCALE_2X;
+ } else if (lightmap_texel_scale < 6.0f) {
+ return GeometryInstance3D::LIGHTMAP_SCALE_4X;
+ }
+
+ return GeometryInstance3D::LIGHTMAP_SCALE_8X;
}
+#endif // DISABLE_DEPRECATED
void GeometryInstance3D::set_gi_mode(GIMode p_mode) {
switch (p_mode) {
@@ -565,8 +599,13 @@ void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_extra_cull_margin", "margin"), &GeometryInstance3D::set_extra_cull_margin);
ClassDB::bind_method(D_METHOD("get_extra_cull_margin"), &GeometryInstance3D::get_extra_cull_margin);
+ ClassDB::bind_method(D_METHOD("set_lightmap_texel_scale", "scale"), &GeometryInstance3D::set_lightmap_texel_scale);
+ ClassDB::bind_method(D_METHOD("get_lightmap_texel_scale"), &GeometryInstance3D::get_lightmap_texel_scale);
+
+#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_lightmap_scale", "scale"), &GeometryInstance3D::set_lightmap_scale);
ClassDB::bind_method(D_METHOD("get_lightmap_scale"), &GeometryInstance3D::get_lightmap_scale);
+#endif // DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("set_gi_mode", "mode"), &GeometryInstance3D::set_gi_mode);
ClassDB::bind_method(D_METHOD("get_gi_mode"), &GeometryInstance3D::get_gi_mode);
@@ -591,7 +630,10 @@ void GeometryInstance3D::_bind_methods() {
ADD_GROUP("Global Illumination", "gi_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_mode", PROPERTY_HINT_ENUM, "Disabled,Static,Dynamic"), "set_gi_mode", "get_gi_mode");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_lightmap_scale", PROPERTY_HINT_ENUM, String::utf8("1×,2×,4×,8×")), "set_lightmap_scale", "get_lightmap_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gi_lightmap_texel_scale", PROPERTY_HINT_RANGE, "0.01,10,0.0001,or_greater"), "set_lightmap_texel_scale", "get_lightmap_texel_scale");
+#ifndef DISABLE_DEPRECATED
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_lightmap_scale", PROPERTY_HINT_ENUM, String::utf8("1×,2×,4×,8×"), PROPERTY_USAGE_NONE), "set_lightmap_scale", "get_lightmap_scale");
+#endif // DISABLE_DEPRECATED
ADD_GROUP("Visibility Range", "visibility_range_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_begin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater,suffix:m"), "set_visibility_range_begin", "get_visibility_range_begin");
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index 9b02c928b7..073fa74573 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -134,7 +134,7 @@ private:
float extra_cull_margin = 0.0;
AABB custom_aabb;
- LightmapScale lightmap_scale = LIGHTMAP_SCALE_1X;
+ float lightmap_texel_scale = 1.0f;
GIMode gi_mode = GI_MODE_STATIC;
bool ignore_occlusion_culling = false;
@@ -185,8 +185,13 @@ public:
void set_gi_mode(GIMode p_mode);
GIMode get_gi_mode() const;
- void set_lightmap_scale(LightmapScale p_scale);
+ void set_lightmap_texel_scale(float p_scale);
+ float get_lightmap_texel_scale() const;
+
+#ifndef DISABLE_DEPRECATED
+ void set_lightmap_scale(GeometryInstance3D::LightmapScale p_scale);
LightmapScale get_lightmap_scale() const;
+#endif // DISABLE_DEPRECATED
void set_instance_shader_parameter(const StringName &p_name, const Variant &p_value);
Variant get_instance_shader_parameter(const StringName &p_name) const;
@@ -203,8 +208,8 @@ public:
};
VARIANT_ENUM_CAST(GeometryInstance3D::ShadowCastingSetting);
-VARIANT_ENUM_CAST(GeometryInstance3D::LightmapScale);
VARIANT_ENUM_CAST(GeometryInstance3D::GIMode);
+VARIANT_ENUM_CAST(GeometryInstance3D::LightmapScale);
VARIANT_ENUM_CAST(GeometryInstance3D::VisibilityRangeFadeMode);
#endif // VISUAL_INSTANCE_3D_H
diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp
index 80ff176a98..5fec7021eb 100644
--- a/scene/3d/voxel_gi.cpp
+++ b/scene/3d/voxel_gi.cpp
@@ -389,6 +389,17 @@ VoxelGI::BakeBeginFunc VoxelGI::bake_begin_function = nullptr;
VoxelGI::BakeStepFunc VoxelGI::bake_step_function = nullptr;
VoxelGI::BakeEndFunc VoxelGI::bake_end_function = nullptr;
+static int voxelizer_plot_bake_base = 0;
+static int voxelizer_plot_bake_total = 0;
+
+static bool voxelizer_plot_bake_step_function(int current, int) {
+ return VoxelGI::bake_step_function((voxelizer_plot_bake_base + current) * 500 / voxelizer_plot_bake_total, RTR("Plotting Meshes"));
+}
+
+static bool voxelizer_sdf_bake_step_function(int current, int total) {
+ return VoxelGI::bake_step_function(500 + current * 500 / total, RTR("Generating Distance Field"));
+}
+
Vector3i VoxelGI::get_estimated_cell_size() const {
static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 };
int cell_subdiv = subdiv_value[subdiv];
@@ -432,22 +443,27 @@ void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) {
_find_meshes(p_from_node, mesh_list);
if (bake_begin_function) {
- bake_begin_function(mesh_list.size() + 1);
+ bake_begin_function();
}
- int pmc = 0;
+ Voxelizer::BakeStepFunc voxelizer_step_func = bake_step_function != nullptr ? voxelizer_plot_bake_step_function : nullptr;
+ voxelizer_plot_bake_total = voxelizer_plot_bake_base = 0;
for (PlotMesh &E : mesh_list) {
- if (bake_step_function) {
- bake_step_function(pmc, RTR("Plotting Meshes") + " " + itos(pmc) + "/" + itos(mesh_list.size()));
+ voxelizer_plot_bake_total += baker.get_bake_steps(E.mesh);
+ }
+ for (PlotMesh &E : mesh_list) {
+ if (baker.plot_mesh(E.local_xform, E.mesh, E.instance_materials, E.override_material, voxelizer_step_func) != Voxelizer::BAKE_RESULT_OK) {
+ baker.end_bake();
+ if (bake_end_function) {
+ bake_end_function();
+ }
+ return;
}
-
- pmc++;
-
- baker.plot_mesh(E.local_xform, E.mesh, E.instance_materials, E.override_material);
+ voxelizer_plot_bake_base += baker.get_bake_steps(E.mesh);
}
if (bake_step_function) {
- bake_step_function(pmc++, RTR("Finishing Plot"));
+ bake_step_function(500, RTR("Finishing Plot"));
}
baker.end_bake();
@@ -476,19 +492,22 @@ void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) {
}
if (bake_step_function) {
- bake_step_function(pmc++, RTR("Generating Distance Field"));
+ bake_step_function(500, RTR("Generating Distance Field"));
}
- Vector<uint8_t> df = baker.get_sdf_3d_image();
+ voxelizer_step_func = bake_step_function != nullptr ? voxelizer_sdf_bake_step_function : nullptr;
- RS::get_singleton()->voxel_gi_set_baked_exposure_normalization(probe_data_new->get_rid(), exposure_normalization);
+ Vector<uint8_t> df;
+ if (baker.get_sdf_3d_image(df, voxelizer_step_func) == Voxelizer::BAKE_RESULT_OK) {
+ RS::get_singleton()->voxel_gi_set_baked_exposure_normalization(probe_data_new->get_rid(), exposure_normalization);
- probe_data_new->allocate(baker.get_to_cell_space_xform(), AABB(-size / 2, size), baker.get_voxel_gi_octree_size(), baker.get_voxel_gi_octree_cells(), baker.get_voxel_gi_data_cells(), df, baker.get_voxel_gi_level_cell_count());
+ probe_data_new->allocate(baker.get_to_cell_space_xform(), AABB(-size / 2, size), baker.get_voxel_gi_octree_size(), baker.get_voxel_gi_octree_cells(), baker.get_voxel_gi_data_cells(), df, baker.get_voxel_gi_level_cell_count());
- set_probe_data(probe_data_new);
+ set_probe_data(probe_data_new);
#ifdef TOOLS_ENABLED
- probe_data_new->set_edited(true); //so it gets saved
+ probe_data_new->set_edited(true); //so it gets saved
#endif
+ }
}
if (bake_end_function) {
diff --git a/scene/3d/voxel_gi.h b/scene/3d/voxel_gi.h
index 7d7787f721..d7e0d74d36 100644
--- a/scene/3d/voxel_gi.h
+++ b/scene/3d/voxel_gi.h
@@ -108,8 +108,8 @@ public:
};
- typedef void (*BakeBeginFunc)(int);
- typedef void (*BakeStepFunc)(int, const String &);
+ typedef void (*BakeBeginFunc)();
+ typedef bool (*BakeStepFunc)(int, const String &);
typedef void (*BakeEndFunc)();
private:
diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp
index 99392e9ba0..1074cad11e 100644
--- a/scene/3d/voxelizer.cpp
+++ b/scene/3d/voxelizer.cpp
@@ -382,8 +382,24 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material
return mc;
}
-void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material) {
- ERR_FAIL_COND_MSG(!p_xform.is_finite(), "Invalid mesh bake transform.");
+int Voxelizer::get_bake_steps(Ref<Mesh> &p_mesh) const {
+ int bake_total = 0;
+ for (int i = 0; i < p_mesh->get_surface_count(); i++) {
+ if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
+ continue; // Only triangles.
+ }
+ Array a = p_mesh->surface_get_arrays(i);
+ Vector<Vector3> vertices = a[Mesh::ARRAY_VERTEX];
+ Vector<int> index = a[Mesh::ARRAY_INDEX];
+ bake_total += (index.size() > 0 ? index.size() : vertices.size()) / 3;
+ }
+ return bake_total;
+}
+
+Voxelizer::BakeResult Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material, BakeStepFunc p_bake_step_func) {
+ ERR_FAIL_COND_V_MSG(!p_xform.is_finite(), BAKE_RESULT_INVALID_PARAMETER, "Invalid mesh bake transform.");
+
+ int bake_total = get_bake_steps(p_mesh), bake_current = 0;
for (int i = 0; i < p_mesh->get_surface_count(); i++) {
if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
@@ -428,6 +444,13 @@ void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const V
Vector2 uvs[3];
Vector3 normal[3];
+ bake_current++;
+ if (p_bake_step_func != nullptr && (bake_current & 2047) == 1) {
+ if (p_bake_step_func(bake_current, bake_total)) {
+ return BAKE_RESULT_CANCELLED;
+ }
+ }
+
for (int k = 0; k < 3; k++) {
vtxs[k] = p_xform.xform(vr[ir[j * 3 + k]]);
}
@@ -460,6 +483,13 @@ void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const V
Vector2 uvs[3];
Vector3 normal[3];
+ bake_current++;
+ if (p_bake_step_func != nullptr && (bake_current & 2047) == 1) {
+ if (p_bake_step_func(bake_current, bake_total)) {
+ return BAKE_RESULT_CANCELLED;
+ }
+ }
+
for (int k = 0; k < 3; k++) {
vtxs[k] = p_xform.xform(vr[j * 3 + k]);
}
@@ -487,6 +517,8 @@ void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const V
}
max_original_cells = bake_cells.size();
+
+ return BAKE_RESULT_OK;
}
void Voxelizer::_sort() {
@@ -821,7 +853,7 @@ static void edt(float *f, int stride, int n) {
#undef square
-Vector<uint8_t> Voxelizer::get_sdf_3d_image() const {
+Voxelizer::BakeResult Voxelizer::get_sdf_3d_image(Vector<uint8_t> &r_image, BakeStepFunc p_bake_step_function) const {
Vector3i octree_size = get_voxel_gi_octree_size();
uint32_t float_count = octree_size.x * octree_size.y * octree_size.z;
@@ -849,9 +881,17 @@ Vector<uint8_t> Voxelizer::get_sdf_3d_image() const {
//process in each direction
+ int bake_total = octree_size.x * 2 + octree_size.y, bake_current = 0;
+
//xy->z
- for (int i = 0; i < octree_size.x; i++) {
+ for (int i = 0; i < octree_size.x; i++, bake_current++) {
+ if (p_bake_step_function) {
+ if (p_bake_step_function(bake_current, bake_total)) {
+ memdelete_arr(work_memory);
+ return BAKE_RESULT_CANCELLED;
+ }
+ }
for (int j = 0; j < octree_size.y; j++) {
edt(&work_memory[i + j * y_mult], z_mult, octree_size.z);
}
@@ -859,23 +899,34 @@ Vector<uint8_t> Voxelizer::get_sdf_3d_image() const {
//xz->y
- for (int i = 0; i < octree_size.x; i++) {
+ for (int i = 0; i < octree_size.x; i++, bake_current++) {
+ if (p_bake_step_function) {
+ if (p_bake_step_function(bake_current, bake_total)) {
+ memdelete_arr(work_memory);
+ return BAKE_RESULT_CANCELLED;
+ }
+ }
for (int j = 0; j < octree_size.z; j++) {
edt(&work_memory[i + j * z_mult], y_mult, octree_size.y);
}
}
//yz->x
- for (int i = 0; i < octree_size.y; i++) {
+ for (int i = 0; i < octree_size.y; i++, bake_current++) {
+ if (p_bake_step_function) {
+ if (p_bake_step_function(bake_current, bake_total)) {
+ memdelete_arr(work_memory);
+ return BAKE_RESULT_CANCELLED;
+ }
+ }
for (int j = 0; j < octree_size.z; j++) {
edt(&work_memory[i * y_mult + j * z_mult], 1, octree_size.x);
}
}
- Vector<uint8_t> image3d;
- image3d.resize(float_count);
+ r_image.resize(float_count);
{
- uint8_t *w = image3d.ptrw();
+ uint8_t *w = r_image.ptrw();
for (uint32_t i = 0; i < float_count; i++) {
uint32_t d = uint32_t(Math::sqrt(work_memory[i]));
if (d == 0) {
@@ -888,7 +939,7 @@ Vector<uint8_t> Voxelizer::get_sdf_3d_image() const {
memdelete_arr(work_memory);
- return image3d;
+ return BAKE_RESULT_OK;
}
#undef INF
diff --git a/scene/3d/voxelizer.h b/scene/3d/voxelizer.h
index 08d018eee9..41e7767308 100644
--- a/scene/3d/voxelizer.h
+++ b/scene/3d/voxelizer.h
@@ -34,6 +34,15 @@
#include "scene/resources/multimesh.h"
class Voxelizer {
+public:
+ enum BakeResult {
+ BAKE_RESULT_OK,
+ BAKE_RESULT_INVALID_PARAMETER,
+ BAKE_RESULT_CANCELLED,
+ };
+
+ typedef bool (*BakeStepFunc)(int, int);
+
private:
enum : uint32_t {
CHILD_EMPTY = 0xFFFFFFFF
@@ -112,7 +121,8 @@ private:
public:
void begin_bake(int p_subdiv, const AABB &p_bounds, float p_exposure_normalization);
- void plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material);
+ int get_bake_steps(Ref<Mesh> &p_mesh) const;
+ BakeResult plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material, BakeStepFunc p_bake_step_function);
void end_bake();
int get_voxel_gi_octree_depth() const;
@@ -121,7 +131,7 @@ public:
Vector<uint8_t> get_voxel_gi_octree_cells() const;
Vector<uint8_t> get_voxel_gi_data_cells() const;
Vector<int> get_voxel_gi_level_cell_count() const;
- Vector<uint8_t> get_sdf_3d_image() const;
+ BakeResult get_sdf_3d_image(Vector<uint8_t> &r_image, BakeStepFunc p_bake_step_function) const;
Ref<MultiMesh> create_debug_multimesh();
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index a2aef60417..d0773fc83f 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -93,7 +93,9 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::process(const AnimationMixer
AnimationMixer::PlaybackInfo pi = p_playback_info;
if (p_playback_info.seeked) {
- pi.delta = get_node_time_info().position - p_playback_info.time;
+ if (p_playback_info.is_external_seeking) {
+ pi.delta = get_node_time_info().position - p_playback_info.time;
+ }
} else {
pi.time = get_node_time_info().position + (backward ? -p_playback_info.delta : p_playback_info.delta);
}
@@ -140,6 +142,12 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe
// 1. Progress for AnimationNode.
bool will_end = Animation::is_greater_or_equal_approx(cur_time + cur_delta, cur_len);
+ bool is_started = p_seek && !p_is_external_seeking && Math::is_zero_approx(cur_time);
+
+ // 1. Progress for AnimationNode.
+ if (is_started && advance_on_start) {
+ cur_time = cur_delta;
+ }
if (cur_loop_mode != Animation::LOOP_NONE) {
if (cur_loop_mode == Animation::LOOP_LINEAR) {
if (!Math::is_zero_approx(cur_len)) {
@@ -232,7 +240,7 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe
// We should use call_deferred since the track keys are still being processed.
if (process_state->tree && !p_test_only) {
// AnimationTree uses seek to 0 "internally" to process the first key of the animation, which is used as the start detection.
- if (p_seek && !p_is_external_seeking && Math::is_zero_approx(cur_playback_time)) {
+ if (is_started) {
process_state->tree->call_deferred(SNAME("emit_signal"), SceneStringName(animation_started), animation);
}
// Finished.
@@ -282,6 +290,14 @@ bool AnimationNodeAnimation::is_backward() const {
return backward;
}
+void AnimationNodeAnimation::set_advance_on_start(bool p_advance_on_start) {
+ advance_on_start = p_advance_on_start;
+}
+
+bool AnimationNodeAnimation::is_advance_on_start() const {
+ return advance_on_start;
+}
+
void AnimationNodeAnimation::set_use_custom_timeline(bool p_use_custom_timeline) {
use_custom_timeline = p_use_custom_timeline;
notify_property_list_changed();
@@ -331,6 +347,9 @@ void AnimationNodeAnimation::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_play_mode", "mode"), &AnimationNodeAnimation::set_play_mode);
ClassDB::bind_method(D_METHOD("get_play_mode"), &AnimationNodeAnimation::get_play_mode);
+ ClassDB::bind_method(D_METHOD("set_advance_on_start", "advance_on_start"), &AnimationNodeAnimation::set_advance_on_start);
+ ClassDB::bind_method(D_METHOD("is_advance_on_start"), &AnimationNodeAnimation::is_advance_on_start);
+
ClassDB::bind_method(D_METHOD("set_use_custom_timeline", "use_custom_timeline"), &AnimationNodeAnimation::set_use_custom_timeline);
ClassDB::bind_method(D_METHOD("is_using_custom_timeline"), &AnimationNodeAnimation::is_using_custom_timeline);
@@ -348,6 +367,7 @@ void AnimationNodeAnimation::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "animation"), "set_animation", "get_animation");
ADD_PROPERTY(PropertyInfo(Variant::INT, "play_mode", PROPERTY_HINT_ENUM, "Forward,Backward"), "set_play_mode", "get_play_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "advance_on_start"), "set_advance_on_start", "is_advance_on_start");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_custom_timeline"), "set_use_custom_timeline", "is_using_custom_timeline");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "timeline_length", PROPERTY_HINT_RANGE, "0.001,60,0.001,or_greater,or_less,hide_slider,suffix:s"), "set_timeline_length", "get_timeline_length");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stretch_time_scale"), "set_stretch_time_scale", "is_stretching_time_scale");
@@ -983,6 +1003,14 @@ String AnimationNodeTimeSeek::get_caption() const {
return "TimeSeek";
}
+void AnimationNodeTimeSeek::set_explicit_elapse(bool p_enable) {
+ explicit_elapse = p_enable;
+}
+
+bool AnimationNodeTimeSeek::is_explicit_elapse() const {
+ return explicit_elapse;
+}
+
AnimationNode::NodeTimeInfo AnimationNodeTimeSeek::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
double cur_seek_pos = get_parameter(seek_pos_request);
@@ -991,7 +1019,7 @@ AnimationNode::NodeTimeInfo AnimationNodeTimeSeek::_process(const AnimationMixer
if (Animation::is_greater_or_equal_approx(cur_seek_pos, 0)) {
pi.time = cur_seek_pos;
pi.seeked = true;
- pi.is_external_seeking = true;
+ pi.is_external_seeking = explicit_elapse;
set_parameter(seek_pos_request, -1.0); // Reset.
}
@@ -1002,6 +1030,12 @@ AnimationNodeTimeSeek::AnimationNodeTimeSeek() {
add_input("in");
}
+void AnimationNodeTimeSeek::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_explicit_elapse", "enable"), &AnimationNodeTimeSeek::set_explicit_elapse);
+ ClassDB::bind_method(D_METHOD("is_explicit_elapse"), &AnimationNodeTimeSeek::is_explicit_elapse);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "explicit_elapse"), "set_explicit_elapse", "is_explicit_elapse");
+}
+
/////////////////////////////////////////////////
bool AnimationNodeTransition::_set(const StringName &p_path, const Variant &p_value) {
diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h
index 2add35d009..c48d799eea 100644
--- a/scene/animation/animation_blend_tree.h
+++ b/scene/animation/animation_blend_tree.h
@@ -38,6 +38,8 @@ class AnimationNodeAnimation : public AnimationRootNode {
StringName animation;
+ bool advance_on_start = false;
+
bool use_custom_timeline = false;
double timeline_length = 1.0;
Animation::LoopMode loop_mode = Animation::LOOP_NONE;
@@ -72,6 +74,9 @@ public:
void set_backward(bool p_backward);
bool is_backward() const;
+ void set_advance_on_start(bool p_advance_on_start);
+ bool is_advance_on_start() const;
+
void set_use_custom_timeline(bool p_use_custom_timeline);
bool is_using_custom_timeline() const;
@@ -297,6 +302,10 @@ class AnimationNodeTimeSeek : public AnimationNode {
GDCLASS(AnimationNodeTimeSeek, AnimationNode);
StringName seek_pos_request = PNAME("seek_request");
+ bool explicit_elapse = true;
+
+protected:
+ static void _bind_methods();
public:
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
@@ -306,6 +315,9 @@ public:
virtual NodeTimeInfo _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override;
+ void set_explicit_elapse(bool p_enable);
+ bool is_explicit_elapse() const;
+
AnimationNodeTimeSeek();
};
diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp
index 0fa6810d23..3e09e425b0 100644
--- a/scene/animation/animation_mixer.cpp
+++ b/scene/animation/animation_mixer.cpp
@@ -33,6 +33,8 @@
#include "core/config/engine.h"
#include "core/config/project_settings.h"
+#include "core/string/print_string.h"
+#include "core/string/string_name.h"
#include "scene/2d/audio_stream_player_2d.h"
#include "scene/animation/animation_player.h"
#include "scene/audio/audio_stream_player.h"
@@ -127,6 +129,9 @@ void AnimationMixer::_validate_property(PropertyInfo &p_property) const {
p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
#endif // TOOLS_ENABLED
+ if (root_motion_track.is_empty() && p_property.name == "root_motion_local") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
}
/* -------------------------------------------- */
@@ -267,6 +272,16 @@ bool AnimationMixer::has_animation_library(const StringName &p_name) const {
return false;
}
+StringName AnimationMixer::get_animation_library_name(const Ref<AnimationLibrary> &p_animation_library) const {
+ ERR_FAIL_COND_V(p_animation_library.is_null(), StringName());
+ for (const AnimationLibraryData &lib : animation_libraries) {
+ if (lib.library == p_animation_library) {
+ return lib.name;
+ }
+ }
+ return StringName();
+}
+
StringName AnimationMixer::find_animation_library(const Ref<Animation> &p_animation) const {
for (const KeyValue<StringName, AnimationData> &E : animation_set) {
if (E.value.animation == p_animation) {
@@ -600,6 +615,22 @@ void AnimationMixer::_init_root_motion_cache() {
root_motion_scale_accumulator = Vector3(1, 1, 1);
}
+void AnimationMixer::_create_track_num_to_track_cashe_for_animation(Ref<Animation> &p_animation) {
+ ERR_FAIL_COND(animation_track_num_to_track_cashe.has(p_animation));
+ LocalVector<TrackCache *> &track_num_to_track_cashe = animation_track_num_to_track_cashe.insert_new(p_animation, LocalVector<TrackCache *>())->value;
+ const Vector<Animation::Track *> &tracks = p_animation->get_tracks();
+
+ track_num_to_track_cashe.resize(tracks.size());
+ for (int i = 0; i < tracks.size(); i++) {
+ TrackCache **track_ptr = track_cache.getptr(tracks[i]->thash);
+ if (track_ptr == nullptr) {
+ track_num_to_track_cashe[i] = nullptr;
+ } else {
+ track_num_to_track_cashe[i] = *track_ptr;
+ }
+ }
+}
+
bool AnimationMixer::_update_caches() {
setup_pass++;
@@ -717,6 +748,15 @@ bool AnimationMixer::_update_caches() {
}
}
+ if (is_value && callback_mode_discrete == ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS) {
+ if (child) {
+ PropertyInfo prop_info;
+ ClassDB::get_property_info(child->get_class_name(), path.get_concatenated_subnames(), &prop_info);
+ if (prop_info.hint == PROPERTY_HINT_ONESHOT) {
+ WARN_PRINT_ED(vformat("%s: '%s', Value Track: '%s' is oneshot property, but will be continuously updated. Consider setting a value other than ANIMATION_CALLBACK_MODE_DISCRETE_FORCE_CONTINUOUS to AnimationMixer.callback_mode_dominant.", mixer_name, String(E), String(path)));
+ }
+ }
+ }
} break;
case Animation::TYPE_POSITION_3D:
case Animation::TYPE_ROTATION_3D:
@@ -928,20 +968,9 @@ bool AnimationMixer::_update_caches() {
}
animation_track_num_to_track_cashe.clear();
- LocalVector<TrackCache *> track_num_to_track_cashe;
for (const StringName &E : sname_list) {
Ref<Animation> anim = get_animation(E);
- const Vector<Animation::Track *> tracks = anim->get_tracks();
- track_num_to_track_cashe.resize(tracks.size());
- for (int i = 0; i < tracks.size(); i++) {
- TrackCache **track_ptr = track_cache.getptr(tracks[i]->thash);
- if (track_ptr == nullptr) {
- track_num_to_track_cashe[i] = nullptr;
- } else {
- track_num_to_track_cashe[i] = *track_ptr;
- }
- }
- animation_track_num_to_track_cashe.insert(anim, track_num_to_track_cashe);
+ _create_track_num_to_track_cashe_for_animation(anim);
}
track_count = idx;
@@ -1074,6 +1103,9 @@ void AnimationMixer::blend_capture(double p_delta) {
capture_cache.remain -= p_delta * capture_cache.step;
if (Animation::is_less_or_equal_approx(capture_cache.remain, 0)) {
+ if (capture_cache.animation.is_valid()) {
+ animation_track_num_to_track_cashe.erase(capture_cache.animation);
+ }
capture_cache.clear();
return;
}
@@ -1192,6 +1224,10 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
}
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
if (track->root_motion && calc_root) {
+ int rot_track = -1;
+ if (root_motion_local) {
+ rot_track = a->find_track(a->track_get_path(i), Animation::TYPE_ROTATION_3D);
+ }
double prev_time = time - delta;
if (!backward) {
if (Animation::is_less_approx(prev_time, start)) {
@@ -1226,41 +1262,92 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
}
}
}
- Vector3 loc[2];
- if (!backward) {
- if (Animation::is_greater_approx(prev_time, time)) {
- Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
- if (err != OK) {
- continue;
+ if (rot_track >= 0) {
+ Vector3 loc[2];
+ Quaternion rot;
+ if (!backward) {
+ if (Animation::is_greater_approx(prev_time, time)) {
+ Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
+ }
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
+ a->try_position_track_interpolate(i, end, &loc[1]);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
+
+ a->try_rotation_track_interpolate(rot_track, end, &rot);
+ rot = post_process_key_value(a, rot_track, rot, t->object_id, t->bone_idx);
+
+ root_motion_cache.loc += rot.xform_inv(loc[1] - loc[0]) * blend;
+ prev_time = start;
}
- loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
- a->try_position_track_interpolate(i, end, &loc[1]);
- loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
- root_motion_cache.loc += (loc[1] - loc[0]) * blend;
- prev_time = start;
+ } else {
+ if (Animation::is_less_approx(prev_time, time)) {
+ Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
+ }
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
+ a->try_position_track_interpolate(i, start, &loc[1]);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
+
+ a->try_rotation_track_interpolate(rot_track, start, &rot);
+ rot = post_process_key_value(a, rot_track, rot, t->object_id, t->bone_idx);
+
+ root_motion_cache.loc += rot.xform_inv(loc[1] - loc[0]) * blend;
+ prev_time = end;
+ }
+ }
+ Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
}
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
+ a->try_position_track_interpolate(i, time, &loc[1]);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
+
+ a->try_rotation_track_interpolate(rot_track, time, &rot);
+ rot = post_process_key_value(a, rot_track, rot, t->object_id, t->bone_idx);
+
+ root_motion_cache.loc += rot.xform_inv(loc[1] - loc[0]) * blend;
+ prev_time = !backward ? start : end;
} else {
- if (Animation::is_less_approx(prev_time, time)) {
- Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
- if (err != OK) {
- continue;
+ Vector3 loc[2];
+ if (!backward) {
+ if (Animation::is_greater_approx(prev_time, time)) {
+ Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
+ }
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
+ a->try_position_track_interpolate(i, end, &loc[1]);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
+ root_motion_cache.loc += (loc[1] - loc[0]) * blend;
+ prev_time = start;
+ }
+ } else {
+ if (Animation::is_less_approx(prev_time, time)) {
+ Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
+ }
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
+ a->try_position_track_interpolate(i, start, &loc[1]);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
+ root_motion_cache.loc += (loc[1] - loc[0]) * blend;
+ prev_time = end;
}
- loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
- a->try_position_track_interpolate(i, start, &loc[1]);
- loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
- root_motion_cache.loc += (loc[1] - loc[0]) * blend;
- prev_time = end;
}
+ Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
+ if (err != OK) {
+ continue;
+ }
+ loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
+ a->try_position_track_interpolate(i, time, &loc[1]);
+ loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
+ root_motion_cache.loc += (loc[1] - loc[0]) * blend;
+ prev_time = !backward ? start : end;
}
- Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]);
- if (err != OK) {
- continue;
- }
- loc[0] = post_process_key_value(a, i, loc[0], t->object_id, t->bone_idx);
- a->try_position_track_interpolate(i, time, &loc[1]);
- loc[1] = post_process_key_value(a, i, loc[1], t->object_id, t->bone_idx);
- root_motion_cache.loc += (loc[1] - loc[0]) * blend;
- prev_time = !backward ? start : end;
}
{
Vector3 loc;
@@ -1335,6 +1422,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
}
rot[0] = post_process_key_value(a, i, rot[0], t->object_id, t->bone_idx);
a->try_rotation_track_interpolate(i, start, &rot[1]);
+ rot[1] = post_process_key_value(a, i, rot[1], t->object_id, t->bone_idx);
root_motion_cache.rot = (root_motion_cache.rot * Quaternion().slerp(rot[0].inverse() * rot[1], blend)).normalized();
prev_time = end;
}
@@ -1410,8 +1498,8 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) {
}
scale[0] = post_process_key_value(a, i, scale[0], t->object_id, t->bone_idx);
a->try_scale_track_interpolate(i, end, &scale[1]);
- root_motion_cache.scale += (scale[1] - scale[0]) * blend;
scale[1] = post_process_key_value(a, i, scale[1], t->object_id, t->bone_idx);
+ root_motion_cache.scale += (scale[1] - scale[0]) * blend;
prev_time = start;
}
} else {
@@ -1982,12 +2070,21 @@ void AnimationMixer::clear_caches() {
void AnimationMixer::set_root_motion_track(const NodePath &p_track) {
root_motion_track = p_track;
+ notify_property_list_changed();
}
NodePath AnimationMixer::get_root_motion_track() const {
return root_motion_track;
}
+void AnimationMixer::set_root_motion_local(bool p_enabled) {
+ root_motion_local = p_enabled;
+}
+
+bool AnimationMixer::is_root_motion_local() const {
+ return root_motion_local;
+}
+
Vector3 AnimationMixer::get_root_motion_position() const {
return root_motion_position;
}
@@ -2205,6 +2302,9 @@ void AnimationMixer::capture(const StringName &p_name, double p_duration, Tween:
capture_cache.step = 1.0 / p_duration;
capture_cache.trans_type = p_trans_type;
capture_cache.ease_type = p_ease_type;
+ if (capture_cache.animation.is_valid()) {
+ animation_track_num_to_track_cashe.erase(capture_cache.animation);
+ }
capture_cache.animation.instantiate();
bool is_valid = false;
@@ -2228,6 +2328,8 @@ void AnimationMixer::capture(const StringName &p_name, double p_duration, Tween:
}
if (!is_valid) {
capture_cache.clear();
+ } else {
+ _create_track_num_to_track_cashe_for_animation(capture_cache.animation);
}
}
@@ -2328,6 +2430,8 @@ void AnimationMixer::_bind_methods() {
/* ---- Root motion accumulator for Skeleton3D ---- */
ClassDB::bind_method(D_METHOD("set_root_motion_track", "path"), &AnimationMixer::set_root_motion_track);
ClassDB::bind_method(D_METHOD("get_root_motion_track"), &AnimationMixer::get_root_motion_track);
+ ClassDB::bind_method(D_METHOD("set_root_motion_local", "enabled"), &AnimationMixer::set_root_motion_local);
+ ClassDB::bind_method(D_METHOD("is_root_motion_local"), &AnimationMixer::is_root_motion_local);
ClassDB::bind_method(D_METHOD("get_root_motion_position"), &AnimationMixer::get_root_motion_position);
ClassDB::bind_method(D_METHOD("get_root_motion_rotation"), &AnimationMixer::get_root_motion_rotation);
@@ -2355,6 +2459,7 @@ void AnimationMixer::_bind_methods() {
ADD_GROUP("Root Motion", "root_motion_");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_motion_track"), "set_root_motion_track", "get_root_motion_track");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "root_motion_local"), "set_root_motion_local", "is_root_motion_local");
ADD_GROUP("Audio", "audio_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "audio_max_polyphony", PROPERTY_HINT_RANGE, "1,127,1"), "set_audio_max_polyphony", "get_audio_max_polyphony");
diff --git a/scene/animation/animation_mixer.h b/scene/animation/animation_mixer.h
index 1906146c56..82deccaa95 100644
--- a/scene/animation/animation_mixer.h
+++ b/scene/animation/animation_mixer.h
@@ -321,6 +321,7 @@ protected:
void _clear_playing_caches();
void _init_root_motion_cache();
bool _update_caches();
+ void _create_track_num_to_track_cashe_for_animation(Ref<Animation> &p_animation);
/* ---- Audio ---- */
AudioServer::PlaybackType playback_type;
@@ -333,6 +334,7 @@ protected:
/* ---- Root motion accumulator for Skeleton3D ---- */
NodePath root_motion_track;
+ bool root_motion_local = false;
Vector3 root_motion_position = Vector3(0, 0, 0);
Quaternion root_motion_rotation = Quaternion(0, 0, 0, 1);
Vector3 root_motion_scale = Vector3(0, 0, 0);
@@ -408,6 +410,7 @@ public:
void get_animation_library_list(List<StringName> *p_animations) const;
Ref<AnimationLibrary> get_animation_library(const StringName &p_name) const;
bool has_animation_library(const StringName &p_name) const;
+ StringName get_animation_library_name(const Ref<AnimationLibrary> &p_animation_library) const;
StringName find_animation_library(const Ref<Animation> &p_animation) const;
Error add_animation_library(const StringName &p_name, const Ref<AnimationLibrary> &p_animation_library);
void remove_animation_library(const StringName &p_name);
@@ -445,6 +448,9 @@ public:
void set_root_motion_track(const NodePath &p_track);
NodePath get_root_motion_track() const;
+ void set_root_motion_local(bool p_enabled);
+ bool is_root_motion_local() const;
+
Vector3 get_root_motion_position() const;
Quaternion get_root_motion_rotation() const;
Vector3 get_root_motion_scale() const;
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index b3a75a75a0..8d24859422 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -164,8 +164,8 @@ void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, f
double delta = p_started ? 0 : p_delta * speed;
double next_pos = cd.pos + delta;
- double start = get_section_start_time();
- double end = get_section_end_time();
+ double start = cd.get_start_time();
+ double end = cd.get_end_time();
Animation::LoopedFlag looped_flag = Animation::LOOPED_FLAG_NONE;
@@ -389,7 +389,7 @@ void AnimationPlayer::play_section_with_markers_backwards(const StringName &p_na
}
void AnimationPlayer::play_section_backwards(const StringName &p_name, double p_start_time, double p_end_time, double p_custom_blend) {
- play_section(p_name, p_start_time, p_end_time, -1, true);
+ play_section(p_name, p_start_time, p_end_time, p_custom_blend, -1, true);
}
void AnimationPlayer::play(const StringName &p_name, double p_custom_blend, float p_custom_scale, bool p_from_end) {
@@ -495,8 +495,8 @@ void AnimationPlayer::play_section(const StringName &p_name, double p_start_time
c.current.start_time = p_start_time;
c.current.end_time = p_end_time;
- double start = get_section_start_time();
- double end = get_section_end_time();
+ double start = playback.current.get_start_time();
+ double end = playback.current.get_end_time();
if (!end_reached) {
playback_queue.clear();
@@ -660,8 +660,8 @@ void AnimationPlayer::seek_internal(double p_time, bool p_update, bool p_update_
}
}
- double start = get_section_start_time();
- double end = get_section_end_time();
+ double start = playback.current.get_start_time();
+ double end = playback.current.get_end_time();
// Clamp the seek position.
p_time = CLAMP(p_time, start, end);
@@ -725,7 +725,7 @@ void AnimationPlayer::set_section(double p_start_time, double p_end_time) {
ERR_FAIL_COND_MSG(Animation::is_greater_or_equal_approx(p_start_time, 0) && Animation::is_greater_or_equal_approx(p_end_time, 0) && Animation::is_greater_or_equal_approx(p_start_time, p_end_time), vformat("Start time %f is greater than end time %f.", p_start_time, p_end_time));
playback.current.start_time = p_start_time;
playback.current.end_time = p_end_time;
- playback.current.pos = CLAMP(playback.current.pos, get_section_start_time(), get_section_end_time());
+ playback.current.pos = CLAMP(playback.current.pos, playback.current.get_start_time(), playback.current.get_end_time());
}
void AnimationPlayer::reset_section() {
@@ -735,18 +735,12 @@ void AnimationPlayer::reset_section() {
double AnimationPlayer::get_section_start_time() const {
ERR_FAIL_NULL_V_MSG(playback.current.from, playback.current.start_time, "AnimationPlayer has no current animation.");
- if (Animation::is_less_approx(playback.current.start_time, 0) || playback.current.start_time > playback.current.from->animation->get_length()) {
- return 0;
- }
- return playback.current.start_time;
+ return playback.current.get_start_time();
}
double AnimationPlayer::get_section_end_time() const {
ERR_FAIL_NULL_V_MSG(playback.current.from, playback.current.end_time, "AnimationPlayer has no current animation.");
- if (Animation::is_less_approx(playback.current.end_time, 0) || playback.current.end_time > playback.current.from->animation->get_length()) {
- return playback.current.from->animation->get_length();
- }
- return playback.current.end_time;
+ return playback.current.get_end_time();
}
bool AnimationPlayer::has_section() const {
@@ -777,7 +771,7 @@ void AnimationPlayer::_stop_internal(bool p_reset, bool p_keep_state) {
_clear_caches();
Playback &c = playback;
// c.blend.clear();
- double start = c.current.from ? get_section_start_time() : 0;
+ double start = c.current.from ? playback.current.get_start_time() : 0;
if (p_reset) {
c.blend.clear();
if (p_keep_state) {
@@ -876,6 +870,20 @@ Tween::EaseType AnimationPlayer::get_auto_capture_ease_type() const {
return auto_capture_ease_type;
}
+#ifdef TOOLS_ENABLED
+void AnimationPlayer::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
+ const String pf = p_function;
+ if (p_idx == 0 && (pf == "play" || pf == "play_backwards" || pf == "has_animation" || pf == "queue")) {
+ List<StringName> al;
+ get_animation_list(&al);
+ for (const StringName &name : al) {
+ r_options->push_back(String(name).quote());
+ }
+ }
+ AnimationMixer::get_argument_options(p_function, p_idx, r_options);
+}
+#endif
+
void AnimationPlayer::_animation_removed(const StringName &p_name, const StringName &p_library) {
AnimationMixer::_animation_removed(p_name, p_library);
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index 06b3eecb89..c87719a2b3 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -70,6 +70,18 @@ private:
float speed_scale = 1.0;
double start_time = 0.0;
double end_time = 0.0;
+ double get_start_time() const {
+ if (from && (Animation::is_less_approx(start_time, 0) || Animation::is_greater_approx(start_time, from->animation->get_length()))) {
+ return 0;
+ }
+ return start_time;
+ }
+ double get_end_time() const {
+ if (from && (Animation::is_less_approx(end_time, 0) || Animation::is_greater_approx(end_time, from->animation->get_length()))) {
+ return from->animation->get_length();
+ }
+ return end_time;
+ }
};
struct Blend {
@@ -178,6 +190,10 @@ public:
void set_auto_capture_ease_type(Tween::EaseType p_auto_capture_ease_type);
Tween::EaseType get_auto_capture_ease_type() const;
+#ifdef TOOLS_ENABLED
+ void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
+#endif
+
void play(const StringName &p_name = StringName(), double p_custom_blend = -1, float p_custom_scale = 1.0, bool p_from_end = false);
void play_section_with_markers(const StringName &p_name = StringName(), const StringName &p_start_marker = StringName(), const StringName &p_end_marker = StringName(), double p_custom_blend = -1, float p_custom_scale = 1.0, bool p_from_end = false);
void play_section(const StringName &p_name = StringName(), double p_start_time = -1, double p_end_time = -1, double p_custom_blend = -1, float p_custom_scale = 1.0, bool p_from_end = false);
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index d676e2acf4..f2871cda79 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -371,7 +371,9 @@ AnimationNode::NodeTimeInfo AnimationNode::process(const AnimationMixer::Playbac
AnimationMixer::PlaybackInfo pi = p_playback_info;
if (p_playback_info.seeked) {
- pi.delta = get_node_time_info().position - p_playback_info.time;
+ if (p_playback_info.is_external_seeking) {
+ pi.delta = get_node_time_info().position - p_playback_info.time;
+ }
} else {
pi.time = get_node_time_info().position + p_playback_info.delta;
}
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index eb25a8db1b..5a2a822ff0 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -91,7 +91,7 @@ public:
if (Math::is_zero_approx(remain)) {
return 0;
}
- return length - position;
+ return remain;
}
};
diff --git a/scene/animation/root_motion_view.cpp b/scene/animation/root_motion_view.cpp
index fd520dadd6..2c0222b3b8 100644
--- a/scene/animation/root_motion_view.cpp
+++ b/scene/animation/root_motion_view.cpp
@@ -94,7 +94,6 @@ void RootMotionView::_notification(int p_what) {
if (has_node(path)) {
Node *node = get_node(path);
-
AnimationMixer *mixer = Object::cast_to<AnimationMixer>(node);
if (mixer && mixer->is_active() && mixer->get_root_motion_track() != NodePath()) {
if (is_processing_internal() && mixer->get_callback_mode_process() == AnimationMixer::ANIMATION_CALLBACK_MODE_PROCESS_PHYSICS) {
@@ -106,12 +105,12 @@ void RootMotionView::_notification(int p_what) {
set_process_internal(true);
set_physics_process_internal(false);
}
+
transform.origin = mixer->get_root_motion_position();
transform.basis = mixer->get_root_motion_rotation(); // Scale is meaningless.
- diff = mixer->get_root_motion_rotation_accumulator();
+ diff = mixer->is_root_motion_local() ? Quaternion() : mixer->get_root_motion_rotation_accumulator();
}
}
-
if (!first && transform == Transform3D()) {
return;
}
diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp
index d4b44a8b69..3996ec9b1e 100644
--- a/scene/audio/audio_stream_player.cpp
+++ b/scene/audio/audio_stream_player.cpp
@@ -262,7 +262,7 @@ void AudioStreamPlayer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume_db", PROPERTY_HINT_RANGE, "-80,24,suffix:dB"), "set_volume_db", "get_volume_db");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,4,0.01,or_greater"), "set_pitch_scale", "get_pitch_scale");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_playing", "is_playing");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_ONESHOT, "", PROPERTY_USAGE_EDITOR), "set_playing", "is_playing");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mix_target", PROPERTY_HINT_ENUM, "Stereo,Surround,Center"), "set_mix_target", "get_mix_target");
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 9d7e2496a2..89f1564775 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -1498,9 +1498,9 @@ void CodeEdit::_line_number_draw_callback(int p_line, int p_gutter, const Rect2
ofs.y += TS->shaped_text_get_ascent(text_rid);
if (rtl) {
- ofs.x = p_region.position.x;
- } else {
ofs.x = p_region.get_end().x - text_size.width;
+ } else {
+ ofs.x = p_region.position.x;
}
Color number_color = get_line_gutter_item_color(p_line, line_number_gutter);
diff --git a/scene/gui/color_mode.h b/scene/gui/color_mode.h
index 0abc90bb44..b762097dc3 100644
--- a/scene/gui/color_mode.h
+++ b/scene/gui/color_mode.h
@@ -33,8 +33,6 @@
#include "scene/gui/color_picker.h"
-struct Color;
-
class ColorMode {
public:
ColorPicker *color_picker = nullptr;
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 997120ff25..72d24f0203 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -30,21 +30,25 @@
#include "color_picker.h"
-#include "core/input/input.h"
#include "core/io/image.h"
-#include "core/math/color.h"
+#include "scene/gui/aspect_ratio_container.h"
#include "scene/gui/color_mode.h"
+#include "scene/gui/grid_container.h"
+#include "scene/gui/label.h"
+#include "scene/gui/line_edit.h"
#include "scene/gui/margin_container.h"
+#include "scene/gui/menu_button.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/popup_menu.h"
+#include "scene/gui/slider.h"
+#include "scene/gui/spin_box.h"
+#include "scene/gui/texture_rect.h"
#include "scene/resources/image_texture.h"
#include "scene/resources/style_box_flat.h"
#include "scene/resources/style_box_texture.h"
#include "scene/theme/theme_db.h"
-#include "servers/display_server.h"
#include "thirdparty/misc/ok_color_shader.h"
-List<Color> ColorPicker::preset_cache;
-List<Color> ColorPicker::recent_preset_cache;
-
void ColorPicker::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -159,10 +163,6 @@ void ColorPicker::_update_theme_item_cache() {
theme_cache.base_scale = get_theme_default_base_scale();
}
-Ref<Shader> ColorPicker::wheel_shader;
-Ref<Shader> ColorPicker::circle_shader;
-Ref<Shader> ColorPicker::circle_ok_color_shader;
-
void ColorPicker::init_shaders() {
wheel_shader.instantiate();
wheel_shader->set_code(R"(
@@ -217,14 +217,14 @@ void fragment() {
circle_ok_color_shader->set_code(OK_COLOR_SHADER + R"(
// ColorPicker ok color hsv circle shader.
-uniform float v = 1.0;
+uniform float ok_hsl_l = 1.0;
void fragment() {
float x = UV.x - 0.5;
float y = UV.y - 0.5;
float h = atan(y, x) / (2.0 * M_PI);
float s = sqrt(x * x + y * y) * 2.0;
- vec3 col = okhsl_to_srgb(vec3(h, s, v));
+ vec3 col = okhsl_to_srgb(vec3(h, s, ok_hsl_l));
x += 0.001;
y += 0.001;
float b = float(sqrt(x * x + y * y) < 0.5);
@@ -387,10 +387,21 @@ void ColorPicker::_slider_value_changed() {
color = modes[current_mode]->get_color();
modes[current_mode]->_value_changed();
- if (current_mode == MODE_HSV || current_mode == MODE_OKHSL) {
+ if (current_mode == MODE_HSV) {
h = sliders[0]->get_value() / 360.0;
s = sliders[1]->get_value() / 100.0;
v = sliders[2]->get_value() / 100.0;
+ ok_hsl_h = color.get_ok_hsl_h();
+ ok_hsl_s = color.get_ok_hsl_s();
+ ok_hsl_l = color.get_ok_hsl_l();
+ last_color = color;
+ } else if (current_mode == MODE_OKHSL) {
+ ok_hsl_h = sliders[0]->get_value() / 360.0;
+ ok_hsl_s = sliders[1]->get_value() / 100.0;
+ ok_hsl_l = sliders[2]->get_value() / 100.0;
+ h = color.get_h();
+ s = color.get_s();
+ v = color.get_v();
last_color = color;
}
@@ -504,20 +515,17 @@ Vector<float> ColorPicker::get_active_slider_values() {
}
void ColorPicker::_copy_color_to_hsv() {
- if (_get_actual_shape() == SHAPE_OKHSL_CIRCLE) {
- h = color.get_ok_hsl_h();
- s = color.get_ok_hsl_s();
- v = color.get_ok_hsl_l();
- } else {
- h = color.get_h();
- s = color.get_s();
- v = color.get_v();
- }
+ ok_hsl_h = color.get_ok_hsl_h();
+ ok_hsl_s = color.get_ok_hsl_s();
+ ok_hsl_l = color.get_ok_hsl_l();
+ h = color.get_h();
+ s = color.get_s();
+ v = color.get_v();
}
void ColorPicker::_copy_hsv_to_color() {
if (_get_actual_shape() == SHAPE_OKHSL_CIRCLE) {
- color.set_ok_hsl(h, s, v, color.a);
+ color.set_ok_hsl(ok_hsl_h, ok_hsl_s, ok_hsl_l, color.a);
} else {
color.set_hsv(h, s, v, color.a);
}
@@ -1201,8 +1209,8 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) {
int x;
int y;
if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) {
- x = center.x + (center.x * Math::cos(h * Math_TAU) * s) - (theme_cache.picker_cursor->get_width() / 2);
- y = center.y + (center.y * Math::sin(h * Math_TAU) * s) - (theme_cache.picker_cursor->get_height() / 2);
+ x = center.x + (center.x * Math::cos((actual_shape == SHAPE_OKHSL_CIRCLE ? ok_hsl_h : h) * Math_TAU) * s) - (theme_cache.picker_cursor->get_width() / 2);
+ y = center.y + (center.y * Math::sin((actual_shape == SHAPE_OKHSL_CIRCLE ? ok_hsl_h : h) * Math_TAU) * s) - (theme_cache.picker_cursor->get_height() / 2);
} else {
real_t corner_x = (c == wheel_uv) ? center.x - Math_SQRT12 * c->get_size().width * 0.42 : 0;
real_t corner_y = (c == wheel_uv) ? center.y - Math_SQRT12 * c->get_size().height * 0.42 : 0;
@@ -1238,11 +1246,11 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) {
Vector<Point2> points;
Vector<Color> colors;
Color col;
- col.set_ok_hsl(h, s, 1);
+ col.set_ok_hsl(ok_hsl_h, ok_hsl_s, 1);
Color col2;
- col2.set_ok_hsl(h, s, 0.5);
+ col2.set_ok_hsl(ok_hsl_h, ok_hsl_s, 0.5);
Color col3;
- col3.set_ok_hsl(h, s, 0);
+ col3.set_ok_hsl(ok_hsl_h, ok_hsl_s, 0);
points.resize(6);
colors.resize(6);
points.set(0, Vector2(c->get_size().x, 0));
@@ -1258,8 +1266,8 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) {
colors.set(4, col2);
colors.set(5, col);
c->draw_polygon(points, colors);
- int y = c->get_size().y - c->get_size().y * CLAMP(v, 0, 1);
- col.set_ok_hsl(h, 1, v);
+ int y = c->get_size().y - c->get_size().y * CLAMP(ok_hsl_l, 0, 1);
+ col.set_ok_hsl(ok_hsl_h, 1, ok_hsl_l);
c->draw_line(Point2(0, y), Point2(c->get_size().x, y), col.inverted());
} else if (actual_shape == SHAPE_VHS_CIRCLE) {
Vector<Point2> points;
@@ -1283,8 +1291,10 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) {
}
} else if (p_which == 2) {
c->draw_rect(Rect2(Point2(), c->get_size()), Color(1, 1, 1));
- if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) {
+ if (actual_shape == SHAPE_VHS_CIRCLE) {
circle_mat->set_shader_parameter("v", v);
+ } else if (actual_shape == SHAPE_OKHSL_CIRCLE) {
+ circle_mat->set_shader_parameter("ok_hsl_l", ok_hsl_l);
}
}
}
@@ -1308,6 +1318,8 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) {
real_t rad = center.angle_to_point(bev->get_position());
h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU;
s = CLAMP(dist / center.x, 0, 1);
+ ok_hsl_h = h;
+ ok_hsl_s = s;
} else {
return;
}
@@ -1375,6 +1387,8 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) {
real_t rad = center.angle_to_point(mev->get_position());
h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU;
s = CLAMP(dist / center.x, 0, 1);
+ ok_hsl_h = h;
+ ok_hsl_s = s;
} else {
if (spinning) {
real_t rad = center.angle_to_point(mev->get_position());
@@ -1412,6 +1426,7 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
float y = CLAMP((float)bev->get_position().y, 0, w_edit->get_size().height);
if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) {
v = 1.0 - (y / w_edit->get_size().height);
+ ok_hsl_l = v;
} else {
h = y / w_edit->get_size().height;
}
@@ -1440,6 +1455,7 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
float y = CLAMP((float)mev->get_position().y, 0, w_edit->get_size().height);
if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) {
v = 1.0 - (y / w_edit->get_size().height);
+ ok_hsl_l = v;
} else {
h = y / w_edit->get_size().height;
}
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index 59540d9ace..c7ad1fb4d9 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -31,28 +31,24 @@
#ifndef COLOR_PICKER_H
#define COLOR_PICKER_H
-#include "scene/gui/aspect_ratio_container.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
-#include "scene/gui/control.h"
-#include "scene/gui/grid_container.h"
-#include "scene/gui/label.h"
-#include "scene/gui/line_edit.h"
-#include "scene/gui/menu_button.h"
-#include "scene/gui/option_button.h"
-#include "scene/gui/panel.h"
#include "scene/gui/popup.h"
-#include "scene/gui/separator.h"
-#include "scene/gui/slider.h"
-#include "scene/gui/spin_box.h"
-#include "scene/gui/texture_rect.h"
-#include "scene/resources/style_box_flat.h"
+class AspectRatioContainer;
class ColorMode;
-class ColorModeRGB;
-class ColorModeHSV;
-class ColorModeRAW;
-class ColorModeOKHSL;
+class ColorPickerShape;
+class GridContainer;
+class HSlider;
+class Label;
+class LineEdit;
+class MarginContainer;
+class MenuButton;
+class OptionButton;
+class PopupMenu;
+class SpinBox;
+class StyleBoxFlat;
+class TextureRect;
class ColorPresetButton : public BaseButton {
GDCLASS(ColorPresetButton, BaseButton);
@@ -110,11 +106,11 @@ public:
static const int SLIDER_COUNT = 4;
private:
- static Ref<Shader> wheel_shader;
- static Ref<Shader> circle_shader;
- static Ref<Shader> circle_ok_color_shader;
- static List<Color> preset_cache;
- static List<Color> recent_preset_cache;
+ static inline Ref<Shader> wheel_shader;
+ static inline Ref<Shader> circle_shader;
+ static inline Ref<Shader> circle_ok_color_shader;
+ static inline List<Color> preset_cache;
+ static inline List<Color> recent_preset_cache;
#ifdef TOOLS_ENABLED
Object *editor_settings = nullptr;
@@ -211,6 +207,11 @@ private:
float h = 0.0;
float s = 0.0;
float v = 0.0;
+
+ float ok_hsl_h = 0.0;
+ float ok_hsl_s = 0.0;
+ float ok_hsl_l = 0.0;
+
Color last_color;
struct ThemeCache {
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 9eda1a256f..e601f16843 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -50,7 +50,7 @@ void FileDialog::popup_file_dialog() {
}
void FileDialog::_focus_file_text() {
- int lp = file->get_text().rfind(".");
+ int lp = file->get_text().rfind_char('.');
if (lp != -1) {
file->select(0, lp);
if (file->is_inside_tree() && !is_part_of_edited_scene()) {
@@ -68,9 +68,9 @@ void FileDialog::_native_popup() {
root = OS::get_singleton()->get_user_data_dir();
}
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG_FILE_EXTRA)) {
- DisplayServer::get_singleton()->file_dialog_with_options_show(get_title(), ProjectSettings::get_singleton()->globalize_path(dir->get_text()), root, file->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), filters, _get_options(), callable_mp(this, &FileDialog::_native_dialog_cb_with_options));
+ DisplayServer::get_singleton()->file_dialog_with_options_show(get_translated_title(), ProjectSettings::get_singleton()->globalize_path(dir->get_text()), root, file->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), processed_filters, _get_options(), callable_mp(this, &FileDialog::_native_dialog_cb_with_options));
} else {
- DisplayServer::get_singleton()->file_dialog_show(get_title(), ProjectSettings::get_singleton()->globalize_path(dir->get_text()), file->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), filters, callable_mp(this, &FileDialog::_native_dialog_cb));
+ DisplayServer::get_singleton()->file_dialog_show(get_translated_title(), ProjectSettings::get_singleton()->globalize_path(dir->get_text()), file->get_text().get_file(), show_hidden_files, DisplayServer::FileDialogMode(mode), processed_filters, callable_mp(this, &FileDialog::_native_dialog_cb));
}
}
@@ -851,37 +851,54 @@ void FileDialog::_filename_filter_selected() {
void FileDialog::update_filters() {
filter->clear();
+ processed_filters.clear();
if (filters.size() > 1) {
String all_filters;
+ String all_filters_full;
const int max_filters = 5;
for (int i = 0; i < MIN(max_filters, filters.size()); i++) {
- String flt = filters[i].get_slice(";", 0).strip_edges();
+ String flt = filters[i].get_slicec(';', 0).strip_edges();
if (i > 0) {
all_filters += ", ";
}
all_filters += flt;
}
+ for (int i = 0; i < filters.size(); i++) {
+ String flt = filters[i].get_slicec(';', 0).strip_edges();
+ if (i > 0) {
+ all_filters_full += ",";
+ }
+ all_filters_full += flt;
+ }
if (max_filters < filters.size()) {
all_filters += ", ...";
}
- filter->add_item(atr(ETR("All Recognized")) + " (" + all_filters + ")");
+ String f = atr(ETR("All Recognized")) + " (" + all_filters + ")";
+ filter->add_item(f);
+ processed_filters.push_back(all_filters_full + ";" + f);
}
for (int i = 0; i < filters.size(); i++) {
- String flt = filters[i].get_slice(";", 0).strip_edges();
+ String flt = filters[i].get_slicec(';', 0).strip_edges();
String desc = filters[i].get_slice(";", 1).strip_edges();
if (desc.length()) {
- filter->add_item(String(tr(desc)) + " (" + flt + ")");
+ String f = atr(desc) + " (" + flt + ")";
+ filter->add_item(f);
+ processed_filters.push_back(flt + ";" + f);
} else {
- filter->add_item("(" + flt + ")");
+ String f = "(" + flt + ")";
+ filter->add_item(f);
+ processed_filters.push_back(flt + ";" + f);
}
}
- filter->add_item(atr(ETR("All Files")) + " (*)");
+ String f = atr(ETR("All Files")) + " (*)";
+ filter->add_item(f);
+ processed_filters.push_back("*.*;" + f);
}
void FileDialog::clear_filename_filter() {
@@ -984,7 +1001,7 @@ void FileDialog::set_current_path(const String &p_path) {
if (!p_path.size()) {
return;
}
- int pos = MAX(p_path.rfind("/"), p_path.rfind("\\"));
+ int pos = MAX(p_path.rfind_char('/'), p_path.rfind_char('\\'));
if (pos == -1) {
set_current_file(p_path);
} else {
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index 28978dbed3..82067ac534 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -101,6 +101,7 @@ private:
Button *show_filename_filter_button = nullptr;
Vector<String> filters;
+ Vector<String> processed_filters;
String file_name_filter;
bool show_filename_filter = false;
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 3f979f7c20..b7c7326172 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -1452,13 +1452,12 @@ void LineEdit::undo() {
return;
}
+ if (!has_undo()) {
+ return;
+ }
+
if (undo_stack_pos == nullptr) {
- if (undo_stack.size() <= 1) {
- return;
- }
undo_stack_pos = undo_stack.back();
- } else if (undo_stack_pos == undo_stack.front()) {
- return;
}
deselect();
@@ -1479,10 +1478,7 @@ void LineEdit::redo() {
return;
}
- if (undo_stack_pos == nullptr) {
- return;
- }
- if (undo_stack_pos == undo_stack.back()) {
+ if (!has_redo()) {
return;
}
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index 79018c40f5..26d164a62d 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -178,7 +178,7 @@ bool OptionButton::_set(const StringName &p_name, const Variant &p_value) {
}
void OptionButton::_focused(int p_which) {
- emit_signal(SNAME("item_focused"), p_which);
+ emit_signal(SNAME("item_focused"), popup->get_item_index(p_which));
}
void OptionButton::_selected(int p_which) {
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 3c04094526..f6ebcc854c 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -474,7 +474,7 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
for (int i = search_from; i < items.size(); i++) {
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
- emit_signal(SNAME("id_focused"), i);
+ emit_signal(SNAME("id_focused"), items[i].id);
scroll_to_item(i);
control->queue_redraw();
set_input_as_handled();
@@ -488,7 +488,7 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
for (int i = 0; i < search_from; i++) {
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
- emit_signal(SNAME("id_focused"), i);
+ emit_signal(SNAME("id_focused"), items[i].id);
scroll_to_item(i);
control->queue_redraw();
set_input_as_handled();
@@ -512,7 +512,7 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
for (int i = search_from; i >= 0; i--) {
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
- emit_signal(SNAME("id_focused"), i);
+ emit_signal(SNAME("id_focused"), items[i].id);
scroll_to_item(i);
control->queue_redraw();
set_input_as_handled();
@@ -526,7 +526,7 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
for (int i = items.size() - 1; i >= search_from; i--) {
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
- emit_signal(SNAME("id_focused"), i);
+ emit_signal(SNAME("id_focused"), items[i].id);
scroll_to_item(i);
control->queue_redraw();
set_input_as_handled();
@@ -692,7 +692,7 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
if (items[i].text.findn(search_string) == 0) {
mouse_over = i;
- emit_signal(SNAME("id_focused"), i);
+ emit_signal(SNAME("id_focused"), items[i].id);
scroll_to_item(i);
control->queue_redraw();
set_input_as_handled();
@@ -1091,7 +1091,7 @@ void PopupMenu::_notification(int p_what) {
for (int i = search_from; i < items.size(); i++) {
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
- emit_signal(SNAME("id_focused"), i);
+ emit_signal(SNAME("id_focused"), items[i].id);
scroll_to_item(i);
control->queue_redraw();
match_found = true;
@@ -1104,7 +1104,7 @@ void PopupMenu::_notification(int p_what) {
for (int i = 0; i < search_from; i++) {
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
- emit_signal(SNAME("id_focused"), i);
+ emit_signal(SNAME("id_focused"), items[i].id);
scroll_to_item(i);
control->queue_redraw();
break;
@@ -1124,7 +1124,7 @@ void PopupMenu::_notification(int p_what) {
for (int i = search_from; i >= 0; i--) {
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
- emit_signal(SNAME("id_focused"), i);
+ emit_signal(SNAME("id_focused"), items[i].id);
scroll_to_item(i);
control->queue_redraw();
match_found = true;
@@ -1137,7 +1137,7 @@ void PopupMenu::_notification(int p_what) {
for (int i = items.size() - 1; i >= search_from; i--) {
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
- emit_signal(SNAME("id_focused"), i);
+ emit_signal(SNAME("id_focused"), items[i].id);
scroll_to_item(i);
control->queue_redraw();
break;
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 26141663c1..b0886a95d7 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -1833,8 +1833,7 @@ void RichTextLabel::_notification(int p_what) {
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_TRANSLATION_CHANGED: {
- // If `text` is empty, it could mean that the tag stack is being used instead. Leave it be.
- if (!text.is_empty()) {
+ if (!stack_externally_modified) {
_apply_translation();
}
@@ -3109,6 +3108,10 @@ void RichTextLabel::add_text(const String &p_text) {
}
void RichTextLabel::_add_item(Item *p_item, bool p_enter, bool p_ensure_newline) {
+ if (!internal_stack_editing) {
+ stack_externally_modified = true;
+ }
+
p_item->parent = current;
p_item->E = current->subitems.push_back(p_item);
p_item->index = current_idx++;
@@ -3382,6 +3385,8 @@ bool RichTextLabel::remove_paragraph(int p_paragraph, bool p_no_invalidate) {
return false;
}
+ stack_externally_modified = true;
+
if (main->lines.size() == 1) {
// Clear all.
main->_clear_children();
@@ -4016,6 +4021,8 @@ void RichTextLabel::clear() {
set_process_internal(false);
MutexLock data_lock(data_mutex);
+ stack_externally_modified = false;
+
main->_clear_children();
current = main;
current_frame = main;
@@ -4845,7 +4852,7 @@ void RichTextLabel::append_text(const String &p_bbcode) {
String tooltip;
bool size_in_percent = false;
if (!bbcode_value.is_empty()) {
- int sep = bbcode_value.find("x");
+ int sep = bbcode_value.find_char('x');
if (sep == -1) {
width = bbcode_value.to_int();
} else {
@@ -5818,11 +5825,19 @@ void RichTextLabel::set_text(const String &p_bbcode) {
return;
}
+ stack_externally_modified = false;
+
text = p_bbcode;
_apply_translation();
}
void RichTextLabel::_apply_translation() {
+ if (text.is_empty()) {
+ return;
+ }
+
+ internal_stack_editing = true;
+
String xl_text = atr(text);
if (use_bbcode) {
parse_bbcode(xl_text);
@@ -5830,6 +5845,8 @@ void RichTextLabel::_apply_translation() {
clear();
add_text(xl_text);
}
+
+ internal_stack_editing = false;
}
String RichTextLabel::get_text() const {
@@ -5843,8 +5860,7 @@ void RichTextLabel::set_use_bbcode(bool p_enable) {
use_bbcode = p_enable;
notify_property_list_changed();
- // If `text` is empty, it could mean that the tag stack is being used instead. Leave it be.
- if (!text.is_empty()) {
+ if (!stack_externally_modified) {
_apply_translation();
}
}
@@ -5854,7 +5870,7 @@ bool RichTextLabel::is_using_bbcode() const {
}
String RichTextLabel::get_parsed_text() const {
- String txt = "";
+ String txt;
Item *it = main;
while (it) {
if (it->type == ITEM_DROPCAP) {
@@ -5881,7 +5897,7 @@ void RichTextLabel::set_text_direction(Control::TextDirection p_text_direction)
if (text_direction != p_text_direction) {
text_direction = p_text_direction;
- if (!text.is_empty()) {
+ if (!stack_externally_modified) {
_apply_translation();
} else {
main->first_invalid_line.store(0); // Invalidate all lines.
@@ -5901,7 +5917,7 @@ void RichTextLabel::set_horizontal_alignment(HorizontalAlignment p_alignment) {
if (default_alignment != p_alignment) {
default_alignment = p_alignment;
- if (!text.is_empty()) {
+ if (!stack_externally_modified) {
_apply_translation();
} else {
main->first_invalid_line.store(0); // Invalidate all lines.
@@ -5920,7 +5936,7 @@ void RichTextLabel::set_justification_flags(BitField<TextServer::JustificationFl
if (default_jst_flags != p_flags) {
default_jst_flags = p_flags;
- if (!text.is_empty()) {
+ if (!stack_externally_modified) {
_apply_translation();
} else {
main->first_invalid_line.store(0); // Invalidate all lines.
@@ -5939,7 +5955,7 @@ void RichTextLabel::set_tab_stops(const PackedFloat32Array &p_tab_stops) {
if (default_tab_stops != p_tab_stops) {
default_tab_stops = p_tab_stops;
- if (!text.is_empty()) {
+ if (!stack_externally_modified) {
_apply_translation();
} else {
main->first_invalid_line.store(0); // Invalidate all lines.
@@ -5958,7 +5974,7 @@ void RichTextLabel::set_structured_text_bidi_override(TextServer::StructuredText
_stop_thread();
st_parser = p_parser;
- if (!text.is_empty()) {
+ if (!stack_externally_modified) {
_apply_translation();
} else {
main->first_invalid_line.store(0); // Invalidate all lines.
@@ -5992,7 +6008,7 @@ void RichTextLabel::set_language(const String &p_language) {
_stop_thread();
language = p_language;
- if (!text.is_empty()) {
+ if (!stack_externally_modified) {
_apply_translation();
} else {
main->first_invalid_line.store(0); // Invalidate all lines.
@@ -6050,7 +6066,7 @@ float RichTextLabel::get_visible_ratio() const {
void RichTextLabel::set_effects(Array p_effects) {
custom_effects = p_effects;
- if ((!text.is_empty()) && use_bbcode) {
+ if (!stack_externally_modified && use_bbcode) {
parse_bbcode(atr(text));
}
}
@@ -6065,7 +6081,7 @@ void RichTextLabel::install_effect(const Variant effect) {
ERR_FAIL_COND_MSG(rteffect.is_null(), "Invalid RichTextEffect resource.");
custom_effects.push_back(effect);
- if ((!text.is_empty()) && use_bbcode) {
+ if (!stack_externally_modified && use_bbcode) {
parse_bbcode(atr(text));
}
}
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index a01da02b27..ef4d17b8aa 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -626,6 +626,9 @@ private:
String text;
void _apply_translation();
+ bool internal_stack_editing = false;
+ bool stack_externally_modified = false;
+
bool fit_content = false;
struct ThemeCache {
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index 01c2b9bffe..2928794551 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -41,7 +41,11 @@ Size2 SpinBox::get_minimum_size() const {
}
void SpinBox::_update_text(bool p_keep_line_edit) {
- String value = String::num(get_value(), Math::range_step_decimals(get_step()));
+ double step = get_step();
+ if (use_custom_arrow_step && custom_arrow_step != 0.0) {
+ step = custom_arrow_step;
+ }
+ String value = String::num(get_value(), Math::range_step_decimals(step));
if (is_localizing_numeral_system()) {
value = TS->format_number(value);
}
@@ -75,6 +79,9 @@ void SpinBox::_text_submitted(const String &p_string) {
text = text.trim_prefix(prefix + " ").trim_suffix(" " + suffix);
Error err = expr->parse(text);
+
+ use_custom_arrow_step = false;
+
if (err != OK) {
// If the expression failed try without converting commas to dots - they might have been for parameter separation.
text = p_string;
@@ -114,8 +121,13 @@ void SpinBox::_line_edit_input(const Ref<InputEvent> &p_event) {
void SpinBox::_range_click_timeout() {
if (!drag.enabled && Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) {
bool up = get_local_mouse_position().y < (get_size().height / 2);
- double step = get_custom_arrow_step() != 0.0 ? get_custom_arrow_step() : get_step();
- set_value(get_value() + (up ? step : -step));
+ double step = get_step();
+ // Arrow button is being pressed, so we also need to set the step to the same value as custom_arrow_step if its not 0.
+ double temp_step = get_custom_arrow_step() != 0.0 ? get_custom_arrow_step() : get_step();
+ _set_step_no_signal(temp_step);
+ set_value(get_value() + (up ? temp_step : -temp_step));
+ _set_step_no_signal(step);
+ use_custom_arrow_step = true;
if (range_click_timer->is_one_shot()) {
range_click_timer->set_wait_time(0.075);
@@ -156,8 +168,7 @@ void SpinBox::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
Ref<InputEventMouseMotion> mm = p_event;
- double step = get_custom_arrow_step() != 0.0 ? get_custom_arrow_step() : get_step();
-
+ double step = get_step();
Vector2 mpos;
bool mouse_on_up_button = false;
bool mouse_on_down_button = false;
@@ -177,7 +188,12 @@ void SpinBox::gui_input(const Ref<InputEvent> &p_event) {
line_edit->grab_focus();
if (mouse_on_up_button || mouse_on_down_button) {
- set_value(get_value() + (mouse_on_up_button ? step : -step));
+ // Arrow button is being pressed, so step is being changed temporarily.
+ double temp_step = get_custom_arrow_step() != 0.0 ? get_custom_arrow_step() : get_step();
+ _set_step_no_signal(temp_step);
+ set_value(get_value() + (mouse_on_up_button ? temp_step : -temp_step));
+ _set_step_no_signal(step);
+ use_custom_arrow_step = true;
}
state_cache.up_button_pressed = mouse_on_up_button;
state_cache.down_button_pressed = mouse_on_down_button;
@@ -193,17 +209,20 @@ void SpinBox::gui_input(const Ref<InputEvent> &p_event) {
case MouseButton::RIGHT: {
line_edit->grab_focus();
if (mouse_on_up_button || mouse_on_down_button) {
+ use_custom_arrow_step = false;
set_value(mouse_on_up_button ? get_max() : get_min());
}
} break;
case MouseButton::WHEEL_UP: {
if (line_edit->is_editing()) {
+ use_custom_arrow_step = false;
set_value(get_value() + step * mb->get_factor());
accept_event();
}
} break;
case MouseButton::WHEEL_DOWN: {
if (line_edit->is_editing()) {
+ use_custom_arrow_step = false;
set_value(get_value() - step * mb->get_factor());
accept_event();
}
@@ -243,6 +262,7 @@ void SpinBox::gui_input(const Ref<InputEvent> &p_event) {
if (drag.enabled) {
drag.diff_y += mm->get_relative().y;
double diff_y = -0.01 * Math::pow(ABS(drag.diff_y), 1.8) * SIGN(drag.diff_y);
+ use_custom_arrow_step = false;
set_value(CLAMP(drag.base_val + step * diff_y, get_min(), get_max()));
} else if (drag.allowed && drag.capture_pos.distance_to(mm->get_position()) > 2) {
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
@@ -519,6 +539,18 @@ void SpinBox::_update_buttons_state_for_current_value() {
}
}
+void SpinBox::_set_step_no_signal(double p_step) {
+ set_block_signals(true);
+ set_step(p_step);
+ set_block_signals(false);
+}
+
+void SpinBox::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "exp_edit") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+}
+
void SpinBox::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_horizontal_alignment", "alignment"), &SpinBox::set_horizontal_alignment);
ClassDB::bind_method(D_METHOD("get_horizontal_alignment"), &SpinBox::get_horizontal_alignment);
diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h
index 294dc3e5d5..564294649c 100644
--- a/scene/gui/spin_box.h
+++ b/scene/gui/spin_box.h
@@ -66,6 +66,7 @@ class SpinBox : public Range {
String suffix;
String last_updated_text;
double custom_arrow_step = 0.0;
+ bool use_custom_arrow_step = false;
void _line_edit_input(const Ref<InputEvent> &p_event);
@@ -133,10 +134,12 @@ class SpinBox : public Range {
void _mouse_exited();
void _update_buttons_state_for_current_value();
+ void _set_step_no_signal(double p_step);
protected:
virtual void gui_input(const Ref<InputEvent> &p_event) override;
void _value_changed(double p_value) override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp
index a443ae9abf..775db65c3f 100644
--- a/scene/gui/subviewport_container.cpp
+++ b/scene/gui/subviewport_container.cpp
@@ -246,6 +246,14 @@ bool SubViewportContainer::_is_propagated_in_gui_input(const Ref<InputEvent> &p_
return false;
}
+void SubViewportContainer::set_consume_drag_and_drop(bool p_enable) {
+ consume_drag_and_drop = p_enable;
+}
+
+bool SubViewportContainer::is_consume_drag_and_drop_enabled() {
+ return consume_drag_and_drop;
+}
+
void SubViewportContainer::add_child_notify(Node *p_child) {
if (Object::cast_to<SubViewport>(p_child)) {
queue_redraw();
@@ -286,8 +294,12 @@ void SubViewportContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stretch_shrink", "amount"), &SubViewportContainer::set_stretch_shrink);
ClassDB::bind_method(D_METHOD("get_stretch_shrink"), &SubViewportContainer::get_stretch_shrink);
+ ClassDB::bind_method(D_METHOD("set_consume_drag_and_drop", "amount"), &SubViewportContainer::set_consume_drag_and_drop);
+ ClassDB::bind_method(D_METHOD("is_consume_drag_and_drop_enabled"), &SubViewportContainer::is_consume_drag_and_drop_enabled);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stretch"), "set_stretch", "is_stretch_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "stretch_shrink", PROPERTY_HINT_RANGE, "1,32,1,or_greater"), "set_stretch_shrink", "get_stretch_shrink");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "consume_drag_and_drop"), "set_consume_drag_and_drop", "is_consume_drag_and_drop_enabled");
GDVIRTUAL_BIND(_propagate_input_event, "event");
}
diff --git a/scene/gui/subviewport_container.h b/scene/gui/subviewport_container.h
index 06420de730..7230615771 100644
--- a/scene/gui/subviewport_container.h
+++ b/scene/gui/subviewport_container.h
@@ -38,6 +38,8 @@ class SubViewportContainer : public Container {
bool stretch = false;
int shrink = 1;
+ bool consume_drag_and_drop = false;
+
void _notify_viewports(int p_notification);
bool _is_propagated_in_gui_input(const Ref<InputEvent> &p_event);
void _send_event_to_viewports(const Ref<InputEvent> &p_event);
@@ -63,6 +65,9 @@ public:
int get_stretch_shrink() const;
void recalc_force_viewport_sizes();
+ void set_consume_drag_and_drop(bool p_enable);
+ bool is_consume_drag_and_drop_enabled();
+
virtual Size2 get_minimum_size() const override;
virtual Vector<int> get_allowed_size_flags_horizontal() const override;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index b1918ff23f..b8bb17eb2a 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -332,6 +332,7 @@ void TextEdit::Text::clear() {
max_line_width_dirty = true;
max_line_height_dirty = true;
+ total_visible_line_count = 0;
Line line;
line.gutters.resize(gutter_count);
@@ -421,6 +422,10 @@ void TextEdit::Text::remove_range(int p_from_line, int p_to_line) {
for (int i = p_from_line; i < p_to_line; i++) {
const Line &text_line = text[i];
+ if (text_line.hidden) {
+ continue;
+ }
+
if (text_line.height == max_line_height) {
max_line_height_dirty = true;
}
@@ -435,6 +440,8 @@ void TextEdit::Text::remove_range(int p_from_line, int p_to_line) {
text.write[(i - diff) + 1] = text[i + 1];
}
text.resize(text.size() - diff);
+
+ ERR_FAIL_COND(total_visible_line_count < 0); // BUG
}
void TextEdit::Text::add_gutter(int p_at) {
@@ -4168,7 +4175,7 @@ void TextEdit::redo() {
}
_push_current_op();
- if (undo_stack_pos == nullptr) {
+ if (!has_redo()) {
return; // Nothing to do.
}
@@ -7303,6 +7310,10 @@ void TextEdit::_paste_internal(int p_caret) {
}
String clipboard = DisplayServer::get_singleton()->clipboard_get();
+ if (clipboard.is_empty()) {
+ // Nothing to paste.
+ return;
+ }
// Paste a full line. Ignore '\r' characters that may have been added to the clipboard by the OS.
if (get_caret_count() == 1 && !has_selection(0) && !cut_copy_line.is_empty() && cut_copy_line == clipboard.replace("\r", "")) {
diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp
index 4ad56d21d3..24c68e0188 100644
--- a/scene/gui/texture_progress_bar.cpp
+++ b/scene/gui/texture_progress_bar.cpp
@@ -608,11 +608,10 @@ int TextureProgressBar::get_fill_mode() {
}
void TextureProgressBar::set_radial_initial_angle(float p_angle) {
- while (p_angle > 360) {
- p_angle -= 360;
- }
- while (p_angle < 0) {
- p_angle += 360;
+ ERR_FAIL_COND_MSG(!Math::is_finite(p_angle), "Angle is non-finite.");
+
+ if (p_angle < 0.0 || p_angle > 360.0) {
+ p_angle = Math::fposmodp(p_angle, 360.0f);
}
if (rad_init_angle == p_angle) {
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index 8526611093..986bd87af2 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -87,7 +87,7 @@ String HTTPRequest::get_header_value(const PackedStringArray &p_headers, const S
String lowwer_case_header_name = p_header_name.to_lower();
for (int i = 0; i < p_headers.size(); i++) {
- if (p_headers[i].find(":") > 0) {
+ if (p_headers[i].find_char(':') > 0) {
Vector<String> parts = p_headers[i].split(":", false, 1);
if (parts.size() > 1 && parts[0].strip_edges().to_lower() == lowwer_case_header_name) {
value = parts[1].strip_edges();
diff --git a/scene/main/missing_node.cpp b/scene/main/missing_node.cpp
index 83672ae5e0..d5a183eab1 100644
--- a/scene/main/missing_node.cpp
+++ b/scene/main/missing_node.cpp
@@ -84,17 +84,17 @@ bool MissingNode::is_recording_properties() const {
PackedStringArray MissingNode::get_configuration_warnings() const {
// The mere existence of this node is warning.
- PackedStringArray ret;
+ PackedStringArray warnings = Node::get_configuration_warnings();
if (!original_scene.is_empty()) {
- ret.push_back(vformat(RTR("This node was an instance of scene '%s', which was no longer available when this scene was loaded."), original_scene));
- ret.push_back(vformat(RTR("Saving current scene will discard instance and all its properties, including editable children edits (if existing).")));
+ warnings.push_back(vformat(RTR("This node was an instance of scene '%s', which was no longer available when this scene was loaded."), original_scene));
+ warnings.push_back(vformat(RTR("Saving current scene will discard instance and all its properties, including editable children edits (if existing).")));
} else if (!original_class.is_empty()) {
- ret.push_back(vformat(RTR("This node was saved as class type '%s', which was no longer available when this scene was loaded."), original_class));
- ret.push_back(RTR("Data from the original node is kept as a placeholder until this type of node is available again. It can hence be safely re-saved without risk of data loss."));
+ warnings.push_back(vformat(RTR("This node was saved as class type '%s', which was no longer available when this scene was loaded."), original_class));
+ warnings.push_back(RTR("Data from the original node is kept as a placeholder until this type of node is available again. It can hence be safely re-saved without risk of data loss."));
} else {
- ret.push_back(RTR("Unrecognized missing node. Check scene dependency errors for details."));
+ warnings.push_back(RTR("Unrecognized missing node. Check scene dependency errors for details."));
}
- return ret;
+ return warnings;
}
void MissingNode::_bind_methods() {
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 8dc7b4a87c..5063f0d6d0 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -3055,11 +3055,12 @@ void Node::_duplicate_signals(const Node *p_original, Node *p_copy) const {
if (copy && copytarget && E.callable.get_method() != StringName()) {
Callable copy_callable = Callable(copytarget, E.callable.get_method());
if (!copy->is_connected(E.signal.get_name(), copy_callable)) {
- int arg_count = E.callable.get_bound_arguments_count();
- if (arg_count > 0) {
+ int unbound_arg_count = E.callable.get_unbound_arguments_count();
+ if (unbound_arg_count > 0) {
+ copy_callable = copy_callable.unbind(unbound_arg_count);
+ }
+ if (E.callable.get_bound_arguments_count() > 0) {
copy_callable = copy_callable.bindv(E.callable.get_bound_arguments());
- } else if (arg_count < 0) {
- copy_callable = copy_callable.unbind(-arg_count);
}
copy->connect(E.signal.get_name(), copy_callable, E.flags);
}
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 1ee99099ec..a0f39462a0 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -330,7 +330,7 @@ void Viewport::_sub_window_update(Window *p_window) {
int close_h_ofs = p_window->theme_cache.close_h_offset;
int close_v_ofs = p_window->theme_cache.close_v_offset;
- TextLine title_text = TextLine(p_window->atr(p_window->get_title()), title_font, font_size);
+ TextLine title_text = TextLine(p_window->get_translated_title(), title_font, font_size);
title_text.set_width(r.size.width - panel->get_minimum_size().x - close_h_ofs);
title_text.set_direction(p_window->is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
int x = (r.size.width - title_text.get_size().x) / 2;
@@ -1931,21 +1931,19 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
}
- // If the tooltip timer isn't running, start it.
- // Otherwise, only reset the timer if the mouse has moved more than 5 pixels.
- if (!is_tooltip_shown && over->can_process() &&
- (gui.tooltip_timer.is_null() ||
- Math::is_zero_approx(gui.tooltip_timer->get_time_left()) ||
- mm->get_relative().length() > 5.0)) {
- if (gui.tooltip_timer.is_valid()) {
- gui.tooltip_timer->release_connections();
- gui.tooltip_timer = Ref<SceneTreeTimer>();
+ // Reset the timer if the mouse has moved more than 5 pixels or has entered a new control.
+ if (!is_tooltip_shown && over->can_process()) {
+ Vector2 new_tooltip_pos = over->get_screen_transform().xform(pos);
+ if (over != gui.tooltip_control || gui.tooltip_pos.distance_squared_to(new_tooltip_pos) > 25) {
+ if (gui.tooltip_timer.is_valid()) {
+ gui.tooltip_timer->release_connections();
+ }
+ gui.tooltip_control = over;
+ gui.tooltip_pos = new_tooltip_pos;
+ gui.tooltip_timer = get_tree()->create_timer(gui.tooltip_delay);
+ gui.tooltip_timer->set_ignore_time_scale(true);
+ gui.tooltip_timer->connect("timeout", callable_mp(this, &Viewport::_gui_show_tooltip));
}
- gui.tooltip_control = over;
- gui.tooltip_pos = over->get_screen_transform().xform(pos);
- gui.tooltip_timer = get_tree()->create_timer(gui.tooltip_delay);
- gui.tooltip_timer->set_ignore_time_scale(true);
- gui.tooltip_timer->connect("timeout", callable_mp(this, &Viewport::_gui_show_tooltip));
}
}
@@ -3062,6 +3060,14 @@ void Viewport::_update_mouse_over(Vector2 p_pos) {
}
v->_update_mouse_over(v->get_final_transform().affine_inverse().xform(pos));
}
+
+ Viewport *section_root = get_section_root_viewport();
+ if (section_root && c->is_consume_drag_and_drop_enabled()) {
+ // Evaluating `consume_drag_and_drop` and adjusting target_control needs to happen
+ // after `_update_mouse_over` in the SubViewports, because otherwise physics picking
+ // would not work inside SubViewports.
+ section_root->gui.target_control = over;
+ }
}
}
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index fc2fe4320b..05904fa8f9 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -303,6 +303,11 @@ String Window::get_title() const {
return title;
}
+String Window::get_translated_title() const {
+ ERR_READ_THREAD_GUARD_V(String());
+ return tr_title;
+}
+
void Window::_settings_changed() {
if (visible && initial_position != WINDOW_INITIAL_POSITION_ABSOLUTE && is_in_edited_scene_root()) {
Size2 screen_size = Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
diff --git a/scene/main/window.h b/scene/main/window.h
index 0994fc6012..a1d95ab91f 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -274,6 +274,7 @@ public:
void set_title(const String &p_title);
String get_title() const;
+ String get_translated_title() const;
void set_initial_position(WindowInitialPosition p_initial_position);
WindowInitialPosition get_initial_position() const;
diff --git a/scene/property_utils.cpp b/scene/property_utils.cpp
index f068e34beb..9cae7d2a3a 100644
--- a/scene/property_utils.cpp
+++ b/scene/property_utils.cpp
@@ -182,7 +182,7 @@ Variant PropertyUtils::get_property_default_value(const Object *p_object, const
// Heuristically check if this is a synthetic property (whatever/0, whatever/1, etc.)
// because they are not in the class DB yet must have a default (null).
String prop_str = String(p_property);
- int p = prop_str.rfind("/");
+ int p = prop_str.rfind_char('/');
if (p != -1 && p < prop_str.length() - 1) {
bool all_digits = true;
for (int i = p + 1; i < prop_str.length(); i++) {
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 315ccaeb8c..ff739bbead 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -243,6 +243,7 @@
#include "scene/3d/light_3d.h"
#include "scene/3d/lightmap_gi.h"
#include "scene/3d/lightmap_probe.h"
+#include "scene/3d/look_at_modifier_3d.h"
#include "scene/3d/marker_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/multimesh_instance_3d.h"
@@ -276,6 +277,7 @@
#include "scene/3d/physics/vehicle_body_3d.h"
#include "scene/3d/reflection_probe.h"
#include "scene/3d/remote_transform_3d.h"
+#include "scene/3d/retarget_modifier_3d.h"
#include "scene/3d/skeleton_3d.h"
#include "scene/3d/skeleton_ik_3d.h"
#include "scene/3d/skeleton_modifier_3d.h"
@@ -593,6 +595,7 @@ void register_scene_types() {
GDREGISTER_CLASS(Marker3D);
GDREGISTER_CLASS(RootMotionView);
GDREGISTER_VIRTUAL_CLASS(SkeletonModifier3D);
+ GDREGISTER_CLASS(RetargetModifier3D);
OS::get_singleton()->yield(); // may take time to init
@@ -611,6 +614,7 @@ void register_scene_types() {
GDREGISTER_CLASS(SkeletonIK3D);
GDREGISTER_CLASS(BoneAttachment3D);
+ GDREGISTER_CLASS(LookAtModifier3D);
GDREGISTER_CLASS(VehicleBody3D);
GDREGISTER_CLASS(VehicleWheel3D);
diff --git a/scene/resources/3d/box_shape_3d.cpp b/scene/resources/3d/box_shape_3d.cpp
index 313aeb1bca..afb03a8ba1 100644
--- a/scene/resources/3d/box_shape_3d.cpp
+++ b/scene/resources/3d/box_shape_3d.cpp
@@ -29,6 +29,8 @@
/**************************************************************************/
#include "box_shape_3d.h"
+
+#include "scene/resources/3d/primitive_meshes.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> BoxShape3D::get_debug_mesh_lines() const {
@@ -47,6 +49,24 @@ Vector<Vector3> BoxShape3D::get_debug_mesh_lines() const {
return lines;
}
+Ref<ArrayMesh> BoxShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
+ Array box_array;
+ box_array.resize(RS::ARRAY_MAX);
+ BoxMesh::create_mesh_array(box_array, size);
+
+ Vector<Color> colors;
+ const PackedVector3Array &verts = box_array[RS::ARRAY_VERTEX];
+ const int32_t verts_size = verts.size();
+ for (int i = 0; i < verts_size; i++) {
+ colors.append(p_modulate);
+ }
+
+ Ref<ArrayMesh> box_mesh = memnew(ArrayMesh);
+ box_array[RS::ARRAY_COLOR] = colors;
+ box_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, box_array);
+ return box_mesh;
+}
+
real_t BoxShape3D::get_enclosing_radius() const {
return size.length() / 2;
}
diff --git a/scene/resources/3d/box_shape_3d.h b/scene/resources/3d/box_shape_3d.h
index 45c1cde5d7..a9137fdcaf 100644
--- a/scene/resources/3d/box_shape_3d.h
+++ b/scene/resources/3d/box_shape_3d.h
@@ -51,6 +51,7 @@ public:
Vector3 get_size() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
BoxShape3D();
diff --git a/scene/resources/3d/capsule_shape_3d.cpp b/scene/resources/3d/capsule_shape_3d.cpp
index 9e16801060..b63bf69aee 100644
--- a/scene/resources/3d/capsule_shape_3d.cpp
+++ b/scene/resources/3d/capsule_shape_3d.cpp
@@ -30,6 +30,7 @@
#include "capsule_shape_3d.h"
+#include "scene/resources/3d/primitive_meshes.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> CapsuleShape3D::get_debug_mesh_lines() const {
@@ -67,6 +68,24 @@ Vector<Vector3> CapsuleShape3D::get_debug_mesh_lines() const {
return points;
}
+Ref<ArrayMesh> CapsuleShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
+ Array capsule_array;
+ capsule_array.resize(RS::ARRAY_MAX);
+ CapsuleMesh::create_mesh_array(capsule_array, radius, height, 32, 8);
+
+ Vector<Color> colors;
+ const PackedVector3Array &verts = capsule_array[RS::ARRAY_VERTEX];
+ const int32_t verts_size = verts.size();
+ for (int i = 0; i < verts_size; i++) {
+ colors.append(p_modulate);
+ }
+
+ Ref<ArrayMesh> capsule_mesh = memnew(ArrayMesh);
+ capsule_array[RS::ARRAY_COLOR] = colors;
+ capsule_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, capsule_array);
+ return capsule_mesh;
+}
+
real_t CapsuleShape3D::get_enclosing_radius() const {
return height * 0.5;
}
diff --git a/scene/resources/3d/capsule_shape_3d.h b/scene/resources/3d/capsule_shape_3d.h
index 90ee3b584a..2ad7fa452c 100644
--- a/scene/resources/3d/capsule_shape_3d.h
+++ b/scene/resources/3d/capsule_shape_3d.h
@@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
+class ArrayMesh;
+
class CapsuleShape3D : public Shape3D {
GDCLASS(CapsuleShape3D, Shape3D);
float radius = 0.5;
@@ -50,6 +52,7 @@ public:
float get_height() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
CapsuleShape3D();
diff --git a/scene/resources/3d/concave_polygon_shape_3d.cpp b/scene/resources/3d/concave_polygon_shape_3d.cpp
index 82b125905f..1254cc4306 100644
--- a/scene/resources/3d/concave_polygon_shape_3d.cpp
+++ b/scene/resources/3d/concave_polygon_shape_3d.cpp
@@ -30,6 +30,7 @@
#include "concave_polygon_shape_3d.h"
+#include "scene/resources/mesh.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() const {
@@ -59,6 +60,23 @@ Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() const {
return points;
}
+Ref<ArrayMesh> ConcavePolygonShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
+ Vector<Color> colors;
+
+ for (int i = 0; i < faces.size(); i++) {
+ colors.push_back(p_modulate);
+ }
+
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[RS::ARRAY_VERTEX] = faces;
+ a[RS::ARRAY_COLOR] = colors;
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
+
+ return mesh;
+}
+
real_t ConcavePolygonShape3D::get_enclosing_radius() const {
Vector<Vector3> data = get_faces();
const Vector3 *read = data.ptr();
diff --git a/scene/resources/3d/concave_polygon_shape_3d.h b/scene/resources/3d/concave_polygon_shape_3d.h
index a5e46474d5..d5e5bc394b 100644
--- a/scene/resources/3d/concave_polygon_shape_3d.h
+++ b/scene/resources/3d/concave_polygon_shape_3d.h
@@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
+class ArrayMesh;
+
class ConcavePolygonShape3D : public Shape3D {
GDCLASS(ConcavePolygonShape3D, Shape3D);
@@ -72,6 +74,7 @@ public:
bool is_backface_collision_enabled() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
ConcavePolygonShape3D();
diff --git a/scene/resources/3d/convex_polygon_shape_3d.cpp b/scene/resources/3d/convex_polygon_shape_3d.cpp
index 586d5f4678..809c089e6c 100644
--- a/scene/resources/3d/convex_polygon_shape_3d.cpp
+++ b/scene/resources/3d/convex_polygon_shape_3d.cpp
@@ -30,6 +30,7 @@
#include "convex_polygon_shape_3d.h"
#include "core/math/convex_hull.h"
+#include "scene/resources/mesh.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() const {
@@ -53,6 +54,44 @@ Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() const {
return Vector<Vector3>();
}
+Ref<ArrayMesh> ConvexPolygonShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
+ const Vector<Vector3> hull_points = get_points();
+
+ Vector<Vector3> verts;
+ Vector<Color> colors;
+ Vector<int> indices;
+
+ if (hull_points.size() >= 3) {
+ Geometry3D::MeshData md;
+ Error err = ConvexHullComputer::convex_hull(hull_points, md);
+ if (err == OK) {
+ verts = md.vertices;
+ for (int i = 0; i < verts.size(); i++) {
+ colors.push_back(p_modulate);
+ }
+ for (const Geometry3D::MeshData::Face &face : md.faces) {
+ const int first_point = face.indices[0];
+ const int indices_count = face.indices.size();
+ for (int i = 1; i < indices_count - 1; i++) {
+ indices.push_back(first_point);
+ indices.push_back(face.indices[i]);
+ indices.push_back(face.indices[i + 1]);
+ }
+ }
+ }
+ }
+
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[RS::ARRAY_VERTEX] = verts;
+ a[RS::ARRAY_COLOR] = colors;
+ a[RS::ARRAY_INDEX] = indices;
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
+
+ return mesh;
+}
+
real_t ConvexPolygonShape3D::get_enclosing_radius() const {
Vector<Vector3> data = get_points();
const Vector3 *read = data.ptr();
diff --git a/scene/resources/3d/convex_polygon_shape_3d.h b/scene/resources/3d/convex_polygon_shape_3d.h
index 7d1ac123c6..2dd4ce66db 100644
--- a/scene/resources/3d/convex_polygon_shape_3d.h
+++ b/scene/resources/3d/convex_polygon_shape_3d.h
@@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
+class ArrayMesh;
+
class ConvexPolygonShape3D : public Shape3D {
GDCLASS(ConvexPolygonShape3D, Shape3D);
Vector<Vector3> points;
@@ -47,6 +49,7 @@ public:
Vector<Vector3> get_points() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
ConvexPolygonShape3D();
diff --git a/scene/resources/3d/cylinder_shape_3d.cpp b/scene/resources/3d/cylinder_shape_3d.cpp
index a91282fd33..700ff5884d 100644
--- a/scene/resources/3d/cylinder_shape_3d.cpp
+++ b/scene/resources/3d/cylinder_shape_3d.cpp
@@ -30,6 +30,7 @@
#include "cylinder_shape_3d.h"
+#include "scene/resources/3d/primitive_meshes.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> CylinderShape3D::get_debug_mesh_lines() const {
@@ -60,6 +61,24 @@ Vector<Vector3> CylinderShape3D::get_debug_mesh_lines() const {
return points;
}
+Ref<ArrayMesh> CylinderShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
+ Array cylinder_array;
+ cylinder_array.resize(RS::ARRAY_MAX);
+ CylinderMesh::create_mesh_array(cylinder_array, radius, radius, height, 32);
+
+ Vector<Color> colors;
+ const PackedVector3Array &verts = cylinder_array[RS::ARRAY_VERTEX];
+ const int32_t verts_size = verts.size();
+ for (int i = 0; i < verts_size; i++) {
+ colors.append(p_modulate);
+ }
+
+ Ref<ArrayMesh> cylinder_mesh = memnew(ArrayMesh);
+ cylinder_array[RS::ARRAY_COLOR] = colors;
+ cylinder_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array);
+ return cylinder_mesh;
+}
+
real_t CylinderShape3D::get_enclosing_radius() const {
return Vector2(radius, height * 0.5).length();
}
diff --git a/scene/resources/3d/cylinder_shape_3d.h b/scene/resources/3d/cylinder_shape_3d.h
index bd57bc2a97..9388cab368 100644
--- a/scene/resources/3d/cylinder_shape_3d.h
+++ b/scene/resources/3d/cylinder_shape_3d.h
@@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
+class ArrayMesh;
+
class CylinderShape3D : public Shape3D {
GDCLASS(CylinderShape3D, Shape3D);
float radius = 0.5;
@@ -49,6 +51,7 @@ public:
float get_height() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
CylinderShape3D();
diff --git a/scene/resources/3d/height_map_shape_3d.cpp b/scene/resources/3d/height_map_shape_3d.cpp
index 5b55b66152..65b1425670 100644
--- a/scene/resources/3d/height_map_shape_3d.cpp
+++ b/scene/resources/3d/height_map_shape_3d.cpp
@@ -31,6 +31,7 @@
#include "height_map_shape_3d.h"
#include "core/io/image.h"
+#include "scene/resources/mesh.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() const {
@@ -82,6 +83,60 @@ Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() const {
return points;
}
+Ref<ArrayMesh> HeightMapShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
+ Vector<Vector3> verts;
+ Vector<Color> colors;
+ Vector<int> indices;
+
+ // This will be slow for large maps...
+
+ if ((map_width != 0) && (map_depth != 0)) {
+ Vector2 size = Vector2(map_width - 1, map_depth - 1) * -0.5;
+ const real_t *r = map_data.ptr();
+
+ for (int d = 0; d <= map_depth - 2; d++) {
+ const int this_row_offset = map_width * d;
+ const int next_row_offset = this_row_offset + map_width;
+
+ for (int w = 0; w <= map_width - 2; w++) {
+ const float height_tl = r[next_row_offset + w];
+ const float height_bl = r[this_row_offset + w];
+ const float height_br = r[this_row_offset + w + 1];
+ const float height_tr = r[next_row_offset + w + 1];
+
+ const int index_offset = verts.size();
+
+ verts.push_back(Vector3(size.x + w, height_tl, size.y + d + 1));
+ verts.push_back(Vector3(size.x + w, height_bl, size.y + d));
+ verts.push_back(Vector3(size.x + w + 1, height_br, size.y + d));
+ verts.push_back(Vector3(size.x + w + 1, height_tr, size.y + d + 1));
+
+ colors.push_back(p_modulate);
+ colors.push_back(p_modulate);
+ colors.push_back(p_modulate);
+ colors.push_back(p_modulate);
+
+ indices.push_back(index_offset);
+ indices.push_back(index_offset + 1);
+ indices.push_back(index_offset + 2);
+ indices.push_back(index_offset);
+ indices.push_back(index_offset + 2);
+ indices.push_back(index_offset + 3);
+ }
+ }
+ }
+
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[RS::ARRAY_VERTEX] = verts;
+ a[RS::ARRAY_COLOR] = colors;
+ a[RS::ARRAY_INDEX] = indices;
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
+
+ return mesh;
+}
+
real_t HeightMapShape3D::get_enclosing_radius() const {
return Vector3(real_t(map_width), max_height - min_height, real_t(map_depth)).length();
}
diff --git a/scene/resources/3d/height_map_shape_3d.h b/scene/resources/3d/height_map_shape_3d.h
index 33ba9c4472..b5be53092d 100644
--- a/scene/resources/3d/height_map_shape_3d.h
+++ b/scene/resources/3d/height_map_shape_3d.h
@@ -33,6 +33,7 @@
#include "scene/resources/3d/shape_3d.h"
+class ArrayMesh;
class Image;
class HeightMapShape3D : public Shape3D {
@@ -62,6 +63,7 @@ public:
void update_map_data_from_image(const Ref<Image> &p_image, real_t p_height_min, real_t p_height_max);
virtual Vector<Vector3> get_debug_mesh_lines() const override;
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
HeightMapShape3D();
diff --git a/scene/resources/3d/primitive_meshes.cpp b/scene/resources/3d/primitive_meshes.cpp
index ceeb73d0ef..4d04ae77b1 100644
--- a/scene/resources/3d/primitive_meshes.cpp
+++ b/scene/resources/3d/primitive_meshes.cpp
@@ -31,6 +31,7 @@
#include "primitive_meshes.h"
#include "core/config/project_settings.h"
+#include "core/math/math_funcs.h"
#include "scene/resources/theme.h"
#include "scene/theme/theme_db.h"
#include "servers/rendering_server.h"
@@ -261,6 +262,9 @@ void PrimitiveMesh::_bind_methods() {
}
void PrimitiveMesh::set_material(const Ref<Material> &p_material) {
+ if (p_material == material) {
+ return;
+ }
material = p_material;
if (!pending_request) {
// just apply it, else it'll happen when _update is called.
@@ -279,6 +283,9 @@ Array PrimitiveMesh::get_mesh_arrays() const {
}
void PrimitiveMesh::set_custom_aabb(const AABB &p_custom) {
+ if (p_custom.is_equal_approx(custom_aabb)) {
+ return;
+ }
custom_aabb = p_custom;
RS::get_singleton()->mesh_set_custom_aabb(mesh, custom_aabb);
emit_changed();
@@ -289,6 +296,9 @@ AABB PrimitiveMesh::get_custom_aabb() const {
}
void PrimitiveMesh::set_flip_faces(bool p_enable) {
+ if (p_enable == flip_faces) {
+ return;
+ }
flip_faces = p_enable;
request_update();
}
@@ -298,12 +308,18 @@ bool PrimitiveMesh::get_flip_faces() const {
}
void PrimitiveMesh::set_add_uv2(bool p_enable) {
+ if (p_enable == add_uv2) {
+ return;
+ }
add_uv2 = p_enable;
_update_lightmap_size();
request_update();
}
void PrimitiveMesh::set_uv2_padding(float p_padding) {
+ if (Math::is_equal_approx(p_padding, uv2_padding)) {
+ return;
+ }
uv2_padding = p_padding;
_update_lightmap_size();
request_update();
@@ -578,6 +594,10 @@ void CapsuleMesh::_bind_methods() {
}
void CapsuleMesh::set_radius(const float p_radius) {
+ if (Math::is_equal_approx(radius, p_radius)) {
+ return;
+ }
+
radius = p_radius;
if (radius > height * 0.5) {
height = radius * 2.0;
@@ -591,6 +611,10 @@ float CapsuleMesh::get_radius() const {
}
void CapsuleMesh::set_height(const float p_height) {
+ if (Math::is_equal_approx(height, p_height)) {
+ return;
+ }
+
height = p_height;
if (radius > height * 0.5) {
radius = height * 0.5;
@@ -604,6 +628,10 @@ float CapsuleMesh::get_height() const {
}
void CapsuleMesh::set_radial_segments(const int p_segments) {
+ if (radial_segments == p_segments) {
+ return;
+ }
+
radial_segments = p_segments > 4 ? p_segments : 4;
request_update();
}
@@ -613,6 +641,10 @@ int CapsuleMesh::get_radial_segments() const {
}
void CapsuleMesh::set_rings(const int p_rings) {
+ if (rings == p_rings) {
+ return;
+ }
+
ERR_FAIL_COND(p_rings < 0);
rings = p_rings;
request_update();
@@ -908,6 +940,10 @@ void BoxMesh::_bind_methods() {
}
void BoxMesh::set_size(const Vector3 &p_size) {
+ if (p_size.is_equal_approx(size)) {
+ return;
+ }
+
size = p_size;
_update_lightmap_size();
request_update();
@@ -918,6 +954,10 @@ Vector3 BoxMesh::get_size() const {
}
void BoxMesh::set_subdivide_width(const int p_divisions) {
+ if (p_divisions == subdivide_w) {
+ return;
+ }
+
subdivide_w = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -927,6 +967,10 @@ int BoxMesh::get_subdivide_width() const {
}
void BoxMesh::set_subdivide_height(const int p_divisions) {
+ if (p_divisions == subdivide_h) {
+ return;
+ }
+
subdivide_h = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -936,6 +980,10 @@ int BoxMesh::get_subdivide_height() const {
}
void BoxMesh::set_subdivide_depth(const int p_divisions) {
+ if (p_divisions == subdivide_d) {
+ return;
+ }
+
subdivide_d = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -1183,6 +1231,10 @@ void CylinderMesh::_bind_methods() {
}
void CylinderMesh::set_top_radius(const float p_radius) {
+ if (Math::is_equal_approx(p_radius, top_radius)) {
+ return;
+ }
+
top_radius = p_radius;
_update_lightmap_size();
request_update();
@@ -1193,6 +1245,10 @@ float CylinderMesh::get_top_radius() const {
}
void CylinderMesh::set_bottom_radius(const float p_radius) {
+ if (Math::is_equal_approx(p_radius, bottom_radius)) {
+ return;
+ }
+
bottom_radius = p_radius;
_update_lightmap_size();
request_update();
@@ -1203,6 +1259,10 @@ float CylinderMesh::get_bottom_radius() const {
}
void CylinderMesh::set_height(const float p_height) {
+ if (Math::is_equal_approx(p_height, height)) {
+ return;
+ }
+
height = p_height;
_update_lightmap_size();
request_update();
@@ -1213,6 +1273,10 @@ float CylinderMesh::get_height() const {
}
void CylinderMesh::set_radial_segments(const int p_segments) {
+ if (p_segments == radial_segments) {
+ return;
+ }
+
radial_segments = p_segments > 4 ? p_segments : 4;
request_update();
}
@@ -1222,6 +1286,10 @@ int CylinderMesh::get_radial_segments() const {
}
void CylinderMesh::set_rings(const int p_rings) {
+ if (p_rings == rings) {
+ return;
+ }
+
ERR_FAIL_COND(p_rings < 0);
rings = p_rings;
request_update();
@@ -1232,6 +1300,10 @@ int CylinderMesh::get_rings() const {
}
void CylinderMesh::set_cap_top(bool p_cap_top) {
+ if (p_cap_top == cap_top) {
+ return;
+ }
+
cap_top = p_cap_top;
request_update();
}
@@ -1241,6 +1313,10 @@ bool CylinderMesh::is_cap_top() const {
}
void CylinderMesh::set_cap_bottom(bool p_cap_bottom) {
+ if (p_cap_bottom == cap_bottom) {
+ return;
+ }
+
cap_bottom = p_cap_bottom;
request_update();
}
@@ -1375,6 +1451,9 @@ void PlaneMesh::_bind_methods() {
}
void PlaneMesh::set_size(const Size2 &p_size) {
+ if (p_size == size) {
+ return;
+ }
size = p_size;
_update_lightmap_size();
request_update();
@@ -1385,6 +1464,9 @@ Size2 PlaneMesh::get_size() const {
}
void PlaneMesh::set_subdivide_width(const int p_divisions) {
+ if (p_divisions == subdivide_w || (subdivide_w == 0 && p_divisions < 0)) {
+ return;
+ }
subdivide_w = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -1394,6 +1476,9 @@ int PlaneMesh::get_subdivide_width() const {
}
void PlaneMesh::set_subdivide_depth(const int p_divisions) {
+ if (p_divisions == subdivide_d || (subdivide_d == 0 && p_divisions < 0)) {
+ return;
+ }
subdivide_d = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -1403,6 +1488,9 @@ int PlaneMesh::get_subdivide_depth() const {
}
void PlaneMesh::set_center_offset(const Vector3 p_offset) {
+ if (p_offset.is_equal_approx(center_offset)) {
+ return;
+ }
center_offset = p_offset;
request_update();
}
@@ -1412,6 +1500,9 @@ Vector3 PlaneMesh::get_center_offset() const {
}
void PlaneMesh::set_orientation(const Orientation p_orientation) {
+ if (p_orientation == orientation) {
+ return;
+ }
orientation = p_orientation;
request_update();
}
@@ -1719,6 +1810,9 @@ void PrismMesh::_bind_methods() {
}
void PrismMesh::set_left_to_right(const float p_left_to_right) {
+ if (Math::is_equal_approx(p_left_to_right, left_to_right)) {
+ return;
+ }
left_to_right = p_left_to_right;
request_update();
}
@@ -1728,6 +1822,9 @@ float PrismMesh::get_left_to_right() const {
}
void PrismMesh::set_size(const Vector3 &p_size) {
+ if (p_size.is_equal_approx(size)) {
+ return;
+ }
size = p_size;
_update_lightmap_size();
request_update();
@@ -1738,6 +1835,9 @@ Vector3 PrismMesh::get_size() const {
}
void PrismMesh::set_subdivide_width(const int p_divisions) {
+ if (p_divisions == subdivide_w || (p_divisions < 0 && subdivide_w == 0)) {
+ return;
+ }
subdivide_w = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -1747,6 +1847,9 @@ int PrismMesh::get_subdivide_width() const {
}
void PrismMesh::set_subdivide_height(const int p_divisions) {
+ if (p_divisions == subdivide_h || (p_divisions < 0 && subdivide_h == 0)) {
+ return;
+ }
subdivide_h = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -1756,6 +1859,9 @@ int PrismMesh::get_subdivide_height() const {
}
void PrismMesh::set_subdivide_depth(const int p_divisions) {
+ if (p_divisions == subdivide_d || (p_divisions < 0 && subdivide_d == 0)) {
+ return;
+ }
subdivide_d = p_divisions > 0 ? p_divisions : 0;
request_update();
}
@@ -1902,6 +2008,9 @@ void SphereMesh::_bind_methods() {
}
void SphereMesh::set_radius(const float p_radius) {
+ if (Math::is_equal_approx(p_radius, radius)) {
+ return;
+ }
radius = p_radius;
_update_lightmap_size();
request_update();
@@ -1912,6 +2021,9 @@ float SphereMesh::get_radius() const {
}
void SphereMesh::set_height(const float p_height) {
+ if (Math::is_equal_approx(height, p_height)) {
+ return;
+ }
height = p_height;
_update_lightmap_size();
request_update();
@@ -1922,6 +2034,9 @@ float SphereMesh::get_height() const {
}
void SphereMesh::set_radial_segments(const int p_radial_segments) {
+ if (p_radial_segments == radial_segments || (radial_segments == 4 && p_radial_segments < 4)) {
+ return;
+ }
radial_segments = p_radial_segments > 4 ? p_radial_segments : 4;
request_update();
}
@@ -1931,6 +2046,9 @@ int SphereMesh::get_radial_segments() const {
}
void SphereMesh::set_rings(const int p_rings) {
+ if (p_rings == rings) {
+ return;
+ }
ERR_FAIL_COND(p_rings < 1);
rings = p_rings;
request_update();
@@ -1941,6 +2059,9 @@ int SphereMesh::get_rings() const {
}
void SphereMesh::set_is_hemisphere(const bool p_is_hemisphere) {
+ if (p_is_hemisphere == is_hemisphere) {
+ return;
+ }
is_hemisphere = p_is_hemisphere;
_update_lightmap_size();
request_update();
@@ -2086,6 +2207,9 @@ void TorusMesh::_bind_methods() {
}
void TorusMesh::set_inner_radius(const float p_inner_radius) {
+ if (Math::is_equal_approx(p_inner_radius, inner_radius)) {
+ return;
+ }
inner_radius = p_inner_radius;
request_update();
}
@@ -2095,6 +2219,9 @@ float TorusMesh::get_inner_radius() const {
}
void TorusMesh::set_outer_radius(const float p_outer_radius) {
+ if (Math::is_equal_approx(p_outer_radius, outer_radius)) {
+ return;
+ }
outer_radius = p_outer_radius;
request_update();
}
@@ -2104,6 +2231,9 @@ float TorusMesh::get_outer_radius() const {
}
void TorusMesh::set_rings(const int p_rings) {
+ if (p_rings == rings) {
+ return;
+ }
ERR_FAIL_COND(p_rings < 3);
rings = p_rings;
request_update();
@@ -2114,6 +2244,9 @@ int TorusMesh::get_rings() const {
}
void TorusMesh::set_ring_segments(const int p_ring_segments) {
+ if (p_ring_segments == ring_segments) {
+ return;
+ }
ERR_FAIL_COND(p_ring_segments < 3);
ring_segments = p_ring_segments;
request_update();
@@ -2143,6 +2276,9 @@ PointMesh::PointMesh() {
// TUBE TRAIL
void TubeTrailMesh::set_radius(const float p_radius) {
+ if (Math::is_equal_approx(p_radius, radius)) {
+ return;
+ }
radius = p_radius;
request_update();
}
@@ -2151,6 +2287,9 @@ float TubeTrailMesh::get_radius() const {
}
void TubeTrailMesh::set_radial_steps(const int p_radial_steps) {
+ if (p_radial_steps == radial_steps) {
+ return;
+ }
ERR_FAIL_COND(p_radial_steps < 3 || p_radial_steps > 128);
radial_steps = p_radial_steps;
request_update();
@@ -2160,6 +2299,9 @@ int TubeTrailMesh::get_radial_steps() const {
}
void TubeTrailMesh::set_sections(const int p_sections) {
+ if (p_sections == sections) {
+ return;
+ }
ERR_FAIL_COND(p_sections < 2 || p_sections > 128);
sections = p_sections;
request_update();
@@ -2169,6 +2311,9 @@ int TubeTrailMesh::get_sections() const {
}
void TubeTrailMesh::set_section_length(float p_section_length) {
+ if (p_section_length == section_length) {
+ return;
+ }
section_length = p_section_length;
request_update();
}
@@ -2177,6 +2322,9 @@ float TubeTrailMesh::get_section_length() const {
}
void TubeTrailMesh::set_section_rings(const int p_section_rings) {
+ if (p_section_rings == section_rings) {
+ return;
+ }
ERR_FAIL_COND(p_section_rings < 1 || p_section_rings > 1024);
section_rings = p_section_rings;
request_update();
@@ -2186,6 +2334,9 @@ int TubeTrailMesh::get_section_rings() const {
}
void TubeTrailMesh::set_cap_top(bool p_cap_top) {
+ if (p_cap_top == cap_top) {
+ return;
+ }
cap_top = p_cap_top;
request_update();
}
@@ -2195,6 +2346,9 @@ bool TubeTrailMesh::is_cap_top() const {
}
void TubeTrailMesh::set_cap_bottom(bool p_cap_bottom) {
+ if (p_cap_bottom == cap_bottom) {
+ return;
+ }
cap_bottom = p_cap_bottom;
request_update();
}
@@ -2501,6 +2655,9 @@ TubeTrailMesh::TubeTrailMesh() {
// RIBBON TRAIL
void RibbonTrailMesh::set_shape(Shape p_shape) {
+ if (p_shape == shape) {
+ return;
+ }
shape = p_shape;
request_update();
}
@@ -2509,6 +2666,9 @@ RibbonTrailMesh::Shape RibbonTrailMesh::get_shape() const {
}
void RibbonTrailMesh::set_size(const float p_size) {
+ if (Math::is_equal_approx(p_size, size)) {
+ return;
+ }
size = p_size;
request_update();
}
@@ -2517,6 +2677,9 @@ float RibbonTrailMesh::get_size() const {
}
void RibbonTrailMesh::set_sections(const int p_sections) {
+ if (p_sections == sections) {
+ return;
+ }
ERR_FAIL_COND(p_sections < 2 || p_sections > 128);
sections = p_sections;
request_update();
@@ -2526,6 +2689,9 @@ int RibbonTrailMesh::get_sections() const {
}
void RibbonTrailMesh::set_section_length(float p_section_length) {
+ if (p_section_length == section_length) {
+ return;
+ }
section_length = p_section_length;
request_update();
}
@@ -2534,6 +2700,9 @@ float RibbonTrailMesh::get_section_length() const {
}
void RibbonTrailMesh::set_section_segments(const int p_section_segments) {
+ if (p_section_segments == section_segments) {
+ return;
+ }
ERR_FAIL_COND(p_section_segments < 1 || p_section_segments > 1024);
section_segments = p_section_segments;
request_update();
diff --git a/scene/resources/3d/separation_ray_shape_3d.cpp b/scene/resources/3d/separation_ray_shape_3d.cpp
index 07e93b8b79..55529be624 100644
--- a/scene/resources/3d/separation_ray_shape_3d.cpp
+++ b/scene/resources/3d/separation_ray_shape_3d.cpp
@@ -30,6 +30,7 @@
#include "separation_ray_shape_3d.h"
+#include "scene/resources/mesh.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> SeparationRayShape3D::get_debug_mesh_lines() const {
@@ -41,6 +42,10 @@ Vector<Vector3> SeparationRayShape3D::get_debug_mesh_lines() const {
return points;
}
+Ref<ArrayMesh> SeparationRayShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
+ return memnew(ArrayMesh);
+}
+
real_t SeparationRayShape3D::get_enclosing_radius() const {
return length;
}
diff --git a/scene/resources/3d/separation_ray_shape_3d.h b/scene/resources/3d/separation_ray_shape_3d.h
index f24f0eae9e..c1c273c448 100644
--- a/scene/resources/3d/separation_ray_shape_3d.h
+++ b/scene/resources/3d/separation_ray_shape_3d.h
@@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
+class ArrayMesh;
+
class SeparationRayShape3D : public Shape3D {
GDCLASS(SeparationRayShape3D, Shape3D);
float length = 1.0;
@@ -50,6 +52,7 @@ public:
bool get_slide_on_slope() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
SeparationRayShape3D();
diff --git a/scene/resources/3d/shape_3d.cpp b/scene/resources/3d/shape_3d.cpp
index 259d82b7a0..a1ee7b85dd 100644
--- a/scene/resources/3d/shape_3d.cpp
+++ b/scene/resources/3d/shape_3d.cpp
@@ -66,6 +66,34 @@ void Shape3D::set_margin(real_t p_margin) {
PhysicsServer3D::get_singleton()->shape_set_margin(shape, margin);
}
+#ifdef DEBUG_ENABLED
+void Shape3D::set_debug_color(const Color &p_color) {
+ if (p_color == debug_color) {
+ return;
+ }
+
+ debug_color = p_color;
+ _update_shape();
+}
+
+Color Shape3D::get_debug_color() const {
+ return debug_color;
+}
+
+void Shape3D::set_debug_fill(bool p_fill) {
+ if (p_fill == debug_fill) {
+ return;
+ }
+
+ debug_fill = p_fill;
+ _update_shape();
+}
+
+bool Shape3D::get_debug_fill() const {
+ return debug_fill;
+}
+#endif // DEBUG_ENABLED
+
Ref<ArrayMesh> Shape3D::get_debug_mesh() {
if (debug_mesh_cache.is_valid()) {
return debug_mesh_cache;
@@ -79,29 +107,57 @@ Ref<ArrayMesh> Shape3D::get_debug_mesh() {
//make mesh
Vector<Vector3> array;
array.resize(lines.size());
- {
- Vector3 *w = array.ptrw();
- for (int i = 0; i < lines.size(); i++) {
- w[i] = lines[i];
- }
+ Vector3 *v = array.ptrw();
+
+ Vector<Color> arraycol;
+ arraycol.resize(lines.size());
+ Color *c = arraycol.ptrw();
+
+ for (int i = 0; i < lines.size(); i++) {
+ v[i] = lines[i];
+ c[i] = debug_color;
}
- Array arr;
- arr.resize(Mesh::ARRAY_MAX);
- arr[Mesh::ARRAY_VERTEX] = array;
+ Array lines_array;
+ lines_array.resize(Mesh::ARRAY_MAX);
+ lines_array[Mesh::ARRAY_VERTEX] = array;
+ lines_array[Mesh::ARRAY_COLOR] = arraycol;
- SceneTree *st = Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop());
+ Ref<StandardMaterial3D> material = get_debug_collision_material();
- debug_mesh_cache->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, arr);
+ debug_mesh_cache->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, lines_array);
+ debug_mesh_cache->surface_set_material(0, material);
- if (st) {
- debug_mesh_cache->surface_set_material(0, st->get_debug_collision_material());
+ if (debug_fill) {
+ Array solid_array = get_debug_arraymesh_faces(debug_color * Color(1.0, 1.0, 1.0, 0.0625))->surface_get_arrays(0);
+ debug_mesh_cache->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, solid_array);
+ debug_mesh_cache->surface_set_material(1, material);
}
}
return debug_mesh_cache;
}
+Ref<Material> Shape3D::get_debug_collision_material() {
+ if (collision_material.is_valid()) {
+ return collision_material;
+ }
+
+ Ref<StandardMaterial3D> material = memnew(StandardMaterial3D);
+ material->set_albedo(Color(1.0, 1.0, 1.0));
+ material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ material->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MIN + 1);
+ material->set_cull_mode(StandardMaterial3D::CULL_BACK);
+ material->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
+ material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
+
+ collision_material = material;
+
+ return collision_material;
+}
+
void Shape3D::_update_shape() {
emit_changed();
debug_mesh_cache.unref();
diff --git a/scene/resources/3d/shape_3d.h b/scene/resources/3d/shape_3d.h
index 5e6cdbe421..e956f4c322 100644
--- a/scene/resources/3d/shape_3d.h
+++ b/scene/resources/3d/shape_3d.h
@@ -34,6 +34,7 @@
#include "core/io/resource.h"
class ArrayMesh;
+class Material;
class Shape3D : public Resource {
GDCLASS(Shape3D, Resource);
@@ -44,6 +45,10 @@ class Shape3D : public Resource {
real_t margin = 0.04;
Ref<ArrayMesh> debug_mesh_cache;
+ Ref<Material> collision_material;
+
+ Color debug_color = Color(0.0, 0.0, 0.0, 0.0);
+ bool debug_fill = true;
protected:
static void _bind_methods();
@@ -51,6 +56,8 @@ protected:
_FORCE_INLINE_ RID get_shape() const { return shape; }
Shape3D(RID p_shape);
+ Ref<Material> get_debug_collision_material();
+
virtual void _update_shape();
public:
@@ -58,6 +65,7 @@ public:
Ref<ArrayMesh> get_debug_mesh();
virtual Vector<Vector3> get_debug_mesh_lines() const = 0; // { return Vector<Vector3>(); }
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const = 0;
/// Returns the radius of a sphere that fully enclose this shape
virtual real_t get_enclosing_radius() const = 0;
@@ -69,6 +77,14 @@ public:
real_t get_margin() const;
void set_margin(real_t p_margin);
+#ifdef DEBUG_ENABLED
+ void set_debug_color(const Color &p_color);
+ Color get_debug_color() const;
+
+ void set_debug_fill(bool p_fill);
+ bool get_debug_fill() const;
+#endif // DEBUG_ENABLED
+
Shape3D();
~Shape3D();
};
diff --git a/scene/resources/3d/sphere_shape_3d.cpp b/scene/resources/3d/sphere_shape_3d.cpp
index 56b78471ec..bdce41c16f 100644
--- a/scene/resources/3d/sphere_shape_3d.cpp
+++ b/scene/resources/3d/sphere_shape_3d.cpp
@@ -30,6 +30,8 @@
#include "sphere_shape_3d.h"
+#include "scene/resources/3d/primitive_meshes.h"
+#include "scene/resources/material.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> SphereShape3D::get_debug_mesh_lines() const {
@@ -54,6 +56,24 @@ Vector<Vector3> SphereShape3D::get_debug_mesh_lines() const {
return points;
}
+Ref<ArrayMesh> SphereShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
+ Array sphere_array;
+ sphere_array.resize(RS::ARRAY_MAX);
+ SphereMesh::create_mesh_array(sphere_array, radius, radius * 2, 32);
+
+ Vector<Color> colors;
+ const PackedVector3Array &verts = sphere_array[RS::ARRAY_VERTEX];
+ const int32_t verts_size = verts.size();
+ for (int i = 0; i < verts_size; i++) {
+ colors.append(p_modulate);
+ }
+
+ Ref<ArrayMesh> sphere_mesh = memnew(ArrayMesh);
+ sphere_array[RS::ARRAY_COLOR] = colors;
+ sphere_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, sphere_array);
+ return sphere_mesh;
+}
+
real_t SphereShape3D::get_enclosing_radius() const {
return radius;
}
diff --git a/scene/resources/3d/sphere_shape_3d.h b/scene/resources/3d/sphere_shape_3d.h
index 8e95cea608..cb0685287d 100644
--- a/scene/resources/3d/sphere_shape_3d.h
+++ b/scene/resources/3d/sphere_shape_3d.h
@@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
+class ArrayMesh;
+
class SphereShape3D : public Shape3D {
GDCLASS(SphereShape3D, Shape3D);
float radius = 0.5f;
@@ -47,6 +49,7 @@ public:
float get_radius() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override;
SphereShape3D();
diff --git a/scene/resources/3d/world_boundary_shape_3d.cpp b/scene/resources/3d/world_boundary_shape_3d.cpp
index beaaddc95e..25f060aa97 100644
--- a/scene/resources/3d/world_boundary_shape_3d.cpp
+++ b/scene/resources/3d/world_boundary_shape_3d.cpp
@@ -30,6 +30,7 @@
#include "world_boundary_shape_3d.h"
+#include "scene/resources/mesh.h"
#include "servers/physics_server_3d.h"
Vector<Vector3> WorldBoundaryShape3D::get_debug_mesh_lines() const {
@@ -61,6 +62,53 @@ Vector<Vector3> WorldBoundaryShape3D::get_debug_mesh_lines() const {
return points;
}
+Ref<ArrayMesh> WorldBoundaryShape3D::get_debug_arraymesh_faces(const Color &p_modulate) const {
+ Plane p = get_plane();
+
+ Vector3 n1 = p.get_any_perpendicular_normal();
+ Vector3 n2 = p.normal.cross(n1).normalized();
+
+ Vector3 pface[4] = {
+ p.normal * p.d + n1 * 10.0 + n2 * 10.0,
+ p.normal * p.d + n1 * 10.0 + n2 * -10.0,
+ p.normal * p.d + n1 * -10.0 + n2 * -10.0,
+ p.normal * p.d + n1 * -10.0 + n2 * 10.0,
+ };
+
+ Vector<Vector3> points = {
+ pface[0],
+ pface[1],
+ pface[2],
+ pface[3],
+ };
+
+ Vector<Color> colors = {
+ p_modulate,
+ p_modulate,
+ p_modulate,
+ p_modulate,
+ };
+
+ Vector<int> indices = {
+ 0,
+ 1,
+ 2,
+ 0,
+ 2,
+ 3,
+ };
+
+ Ref<ArrayMesh> mesh = memnew(ArrayMesh);
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[RS::ARRAY_VERTEX] = points;
+ a[RS::ARRAY_COLOR] = colors;
+ a[RS::ARRAY_INDEX] = indices;
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a);
+
+ return mesh;
+}
+
void WorldBoundaryShape3D::_update_shape() {
PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), plane);
Shape3D::_update_shape();
diff --git a/scene/resources/3d/world_boundary_shape_3d.h b/scene/resources/3d/world_boundary_shape_3d.h
index 06cff6aa9a..456316df2e 100644
--- a/scene/resources/3d/world_boundary_shape_3d.h
+++ b/scene/resources/3d/world_boundary_shape_3d.h
@@ -33,6 +33,8 @@
#include "scene/resources/3d/shape_3d.h"
+class ArrayMesh;
+
class WorldBoundaryShape3D : public Shape3D {
GDCLASS(WorldBoundaryShape3D, Shape3D);
Plane plane;
@@ -46,6 +48,7 @@ public:
const Plane &get_plane() const;
virtual Vector<Vector3> get_debug_mesh_lines() const override;
+ virtual Ref<ArrayMesh> get_debug_arraymesh_faces(const Color &p_modulate) const override;
virtual real_t get_enclosing_radius() const override {
// Should be infinite?
return 0;
diff --git a/scene/resources/animation_library.cpp b/scene/resources/animation_library.cpp
index 22666876ae..92612fc3d7 100644
--- a/scene/resources/animation_library.cpp
+++ b/scene/resources/animation_library.cpp
@@ -125,6 +125,10 @@ void AnimationLibrary::get_animation_list(List<StringName> *p_animations) const
}
}
+int AnimationLibrary::get_animation_list_size() const {
+ return animations.size();
+}
+
void AnimationLibrary::_set_data(const Dictionary &p_data) {
for (KeyValue<StringName, Ref<Animation>> &K : animations) {
K.value->disconnect_changed(callable_mp(this, &AnimationLibrary::_animation_changed));
@@ -166,6 +170,7 @@ void AnimationLibrary::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_animation", "name"), &AnimationLibrary::has_animation);
ClassDB::bind_method(D_METHOD("get_animation", "name"), &AnimationLibrary::get_animation);
ClassDB::bind_method(D_METHOD("get_animation_list"), &AnimationLibrary::_get_animation_list);
+ ClassDB::bind_method(D_METHOD("get_animation_list_size"), &AnimationLibrary::get_animation_list_size);
ClassDB::bind_method(D_METHOD("_set_data", "data"), &AnimationLibrary::_set_data);
ClassDB::bind_method(D_METHOD("_get_data"), &AnimationLibrary::_get_data);
diff --git a/scene/resources/animation_library.h b/scene/resources/animation_library.h
index 00baf9d302..794f142744 100644
--- a/scene/resources/animation_library.h
+++ b/scene/resources/animation_library.h
@@ -61,6 +61,7 @@ public:
bool has_animation(const StringName &p_name) const;
Ref<Animation> get_animation(const StringName &p_name) const;
void get_animation_list(List<StringName> *p_animations) const;
+ int get_animation_list_size() const;
#ifdef TOOLS_ENABLED
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index 8926eb1d51..91d3757590 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -479,6 +479,9 @@ void Curve::set_bake_resolution(int p_resolution) {
}
real_t Curve::sample_baked(real_t p_offset) const {
+ // Make sure that p_offset is finite.
+ ERR_FAIL_COND_V_MSG(!Math::is_finite(p_offset), 0, "Offset is non-finite");
+
if (_baked_cache_dirty) {
// Last-second bake if not done already
const_cast<Curve *>(this)->bake();
@@ -981,6 +984,9 @@ Transform2D Curve2D::_sample_posture(Interval p_interval) const {
}
Vector2 Curve2D::sample_baked(real_t p_offset, bool p_cubic) const {
+ // Make sure that p_offset is finite.
+ ERR_FAIL_COND_V_MSG(!Math::is_finite(p_offset), Vector2(), "Offset is non-finite");
+
if (baked_cache_dirty) {
_bake();
}
@@ -1000,6 +1006,9 @@ Vector2 Curve2D::sample_baked(real_t p_offset, bool p_cubic) const {
}
Transform2D Curve2D::sample_baked_with_rotation(real_t p_offset, bool p_cubic) const {
+ // Make sure that p_offset is finite.
+ ERR_FAIL_COND_V_MSG(!Math::is_finite(p_offset), Transform2D(), "Offset is non-finite");
+
if (baked_cache_dirty) {
_bake();
}
@@ -1454,6 +1463,9 @@ void Curve3D::_remove_point(int p_index) {
void Curve3D::remove_point(int p_index) {
_remove_point(p_index);
+ if (closed && points.size() < 2) {
+ set_closed(false);
+ }
notify_property_list_changed();
}
@@ -1470,15 +1482,25 @@ Vector3 Curve3D::sample(int p_index, real_t p_offset) const {
ERR_FAIL_COND_V(pc == 0, Vector3());
if (p_index >= pc - 1) {
- return points[pc - 1].position;
+ if (!closed) {
+ return points[pc - 1].position;
+ } else {
+ p_index = pc - 1;
+ }
} else if (p_index < 0) {
return points[0].position;
}
Vector3 p0 = points[p_index].position;
Vector3 p1 = p0 + points[p_index].out;
- Vector3 p3 = points[p_index + 1].position;
- Vector3 p2 = p3 + points[p_index + 1].in;
+ Vector3 p3, p2;
+ if (!closed || p_index < pc - 1) {
+ p3 = points[p_index + 1].position;
+ p2 = p3 + points[p_index + 1].in;
+ } else {
+ p3 = points[0].position;
+ p2 = p3 + points[0].in;
+ }
return p0.bezier_interpolate(p1, p2, p3, p_offset);
}
@@ -1596,13 +1618,16 @@ void Curve3D::_bake() const {
{
Vector<RBMap<real_t, Vector3>> midpoints = _tessellate_even_length(10, bake_interval);
+ const int num_intervals = closed ? points.size() : points.size() - 1;
+
#ifdef TOOLS_ENABLED
- points_in_cache.resize(points.size());
+ points_in_cache.resize(closed ? (points.size() + 1) : points.size());
points_in_cache.set(0, 0);
#endif
+ // Point Count: Begins at 1 to account for the last point.
int pc = 1;
- for (int i = 0; i < points.size() - 1; i++) {
+ for (int i = 0; i < num_intervals; i++) {
pc++;
pc += midpoints[i].size();
#ifdef TOOLS_ENABLED
@@ -1625,18 +1650,29 @@ void Curve3D::_bake() const {
btw[0] = points[0].tilt;
int pidx = 0;
- for (int i = 0; i < points.size() - 1; i++) {
+ for (int i = 0; i < num_intervals; i++) {
for (const KeyValue<real_t, Vector3> &E : midpoints[i]) {
pidx++;
bpw[pidx] = E.value;
- bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, E.key);
- btw[pidx] = Math::lerp(points[i].tilt, points[i + 1].tilt, E.key);
+ if (!closed || i < num_intervals - 1) {
+ bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, E.key);
+ btw[pidx] = Math::lerp(points[i].tilt, points[i + 1].tilt, E.key);
+ } else {
+ bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[0].position + points[0].in, points[0].position, E.key);
+ btw[pidx] = Math::lerp(points[i].tilt, points[0].tilt, E.key);
+ }
}
pidx++;
- bpw[pidx] = points[i + 1].position;
- bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, 1.0);
- btw[pidx] = points[i + 1].tilt;
+ if (!closed || i < num_intervals - 1) {
+ bpw[pidx] = points[i + 1].position;
+ bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[i + 1].position + points[i + 1].in, points[i + 1].position, 1.0);
+ btw[pidx] = points[i + 1].tilt;
+ } else {
+ bpw[pidx] = points[0].position;
+ bfw[pidx] = _calculate_tangent(points[i].position, points[i].position + points[i].out, points[0].position + points[0].in, points[0].position, 1.0);
+ btw[pidx] = points[0].tilt;
+ }
}
// Recalculate the baked distances.
@@ -1881,6 +1917,9 @@ Basis Curve3D::get_point_baked_posture(int p_index, bool p_apply_tilt) const {
#endif
Vector3 Curve3D::sample_baked(real_t p_offset, bool p_cubic) const {
+ // Make sure that p_offset is finite.
+ ERR_FAIL_COND_V_MSG(!Math::is_finite(p_offset), Vector3(), "Offset is non-finite");
+
if (baked_cache_dirty) {
_bake();
}
@@ -1900,6 +1939,9 @@ Vector3 Curve3D::sample_baked(real_t p_offset, bool p_cubic) const {
}
Transform3D Curve3D::sample_baked_with_rotation(real_t p_offset, bool p_cubic, bool p_apply_tilt) const {
+ // Make sure that p_offset is finite.
+ ERR_FAIL_COND_V_MSG(!Math::is_finite(p_offset), Transform3D(), "Offset is non-finite");
+
if (baked_cache_dirty) {
_bake();
}
@@ -1929,6 +1971,9 @@ Transform3D Curve3D::sample_baked_with_rotation(real_t p_offset, bool p_cubic, b
}
real_t Curve3D::sample_baked_tilt(real_t p_offset) const {
+ // Make sure that p_offset is finite.
+ ERR_FAIL_COND_V_MSG(!Math::is_finite(p_offset), 0, "Offset is non-finite");
+
if (baked_cache_dirty) {
_bake();
}
@@ -1948,6 +1993,9 @@ real_t Curve3D::sample_baked_tilt(real_t p_offset) const {
}
Vector3 Curve3D::sample_baked_up_vector(real_t p_offset, bool p_apply_tilt) const {
+ // Make sure that p_offset is finite.
+ ERR_FAIL_COND_V_MSG(!Math::is_finite(p_offset), Vector3(0, 1, 0), "Offset is non-finite");
+
if (baked_cache_dirty) {
_bake();
}
@@ -2075,6 +2123,20 @@ real_t Curve3D::get_closest_offset(const Vector3 &p_to_point) const {
return nearest;
}
+void Curve3D::set_closed(bool p_closed) {
+ if (closed == p_closed) {
+ return;
+ }
+
+ closed = p_closed;
+ mark_dirty();
+ notify_property_list_changed();
+}
+
+bool Curve3D::is_closed() const {
+ return closed;
+}
+
void Curve3D::set_bake_interval(real_t p_tolerance) {
bake_interval = p_tolerance;
mark_dirty();
@@ -2153,11 +2215,17 @@ PackedVector3Array Curve3D::tessellate(int p_max_stages, real_t p_tolerance) con
}
Vector<RBMap<real_t, Vector3>> midpoints;
- midpoints.resize(points.size() - 1);
+ const int num_intervals = closed ? points.size() : points.size() - 1;
+ midpoints.resize(num_intervals);
+ // Point Count: Begins at 1 to account for the last point.
int pc = 1;
- for (int i = 0; i < points.size() - 1; i++) {
- _bake_segment3d(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[i + 1].position, points[i + 1].in, 0, p_max_stages, p_tolerance);
+ for (int i = 0; i < num_intervals; i++) {
+ if (!closed || i < num_intervals - 1) {
+ _bake_segment3d(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[i + 1].position, points[i + 1].in, 0, p_max_stages, p_tolerance);
+ } else {
+ _bake_segment3d(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[0].position, points[0].in, 0, p_max_stages, p_tolerance);
+ }
pc++;
pc += midpoints[i].size();
}
@@ -2167,14 +2235,18 @@ PackedVector3Array Curve3D::tessellate(int p_max_stages, real_t p_tolerance) con
bpw[0] = points[0].position;
int pidx = 0;
- for (int i = 0; i < points.size() - 1; i++) {
+ for (int i = 0; i < num_intervals; i++) {
for (const KeyValue<real_t, Vector3> &E : midpoints[i]) {
pidx++;
bpw[pidx] = E.value;
}
pidx++;
- bpw[pidx] = points[i + 1].position;
+ if (!closed || i < num_intervals - 1) {
+ bpw[pidx] = points[i + 1].position;
+ } else {
+ bpw[pidx] = points[0].position;
+ }
}
return tess;
@@ -2184,10 +2256,15 @@ Vector<RBMap<real_t, Vector3>> Curve3D::_tessellate_even_length(int p_max_stages
Vector<RBMap<real_t, Vector3>> midpoints;
ERR_FAIL_COND_V_MSG(points.size() < 2, midpoints, "Curve must have at least 2 control point");
- midpoints.resize(points.size() - 1);
+ const int num_intervals = closed ? points.size() : points.size() - 1;
+ midpoints.resize(num_intervals);
- for (int i = 0; i < points.size() - 1; i++) {
- _bake_segment3d_even_length(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[i + 1].position, points[i + 1].in, 0, p_max_stages, p_length);
+ for (int i = 0; i < num_intervals; i++) {
+ if (!closed || i < num_intervals - 1) {
+ _bake_segment3d_even_length(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[i + 1].position, points[i + 1].in, 0, p_max_stages, p_length);
+ } else {
+ _bake_segment3d_even_length(midpoints.write[i], 0, 1, points[i].position, points[i].out, points[0].position, points[0].in, 0, p_max_stages, p_length);
+ }
}
return midpoints;
}
@@ -2200,8 +2277,10 @@ PackedVector3Array Curve3D::tessellate_even_length(int p_max_stages, real_t p_le
return tess;
}
+ const int num_intervals = closed ? points.size() : points.size() - 1;
+ // Point Count: Begins at 1 to account for the last point.
int pc = 1;
- for (int i = 0; i < points.size() - 1; i++) {
+ for (int i = 0; i < num_intervals; i++) {
pc++;
pc += midpoints[i].size();
}
@@ -2211,14 +2290,18 @@ PackedVector3Array Curve3D::tessellate_even_length(int p_max_stages, real_t p_le
bpw[0] = points[0].position;
int pidx = 0;
- for (int i = 0; i < points.size() - 1; i++) {
+ for (int i = 0; i < num_intervals; i++) {
for (const KeyValue<real_t, Vector3> &E : midpoints[i]) {
pidx++;
bpw[pidx] = E.value;
}
pidx++;
- bpw[pidx] = points[i + 1].position;
+ if (!closed || i < num_intervals - 1) {
+ bpw[pidx] = points[i + 1].position;
+ } else {
+ bpw[pidx] = points[0].position;
+ }
}
return tess;
@@ -2274,13 +2357,13 @@ void Curve3D::_get_property_list(List<PropertyInfo> *p_list) const {
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
- if (i != 0) {
+ if (closed || i != 0) {
pi = PropertyInfo(Variant::VECTOR3, vformat("point_%d/in", i));
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
}
- if (i != points.size() - 1) {
+ if (closed || i != points.size() - 1) {
pi = PropertyInfo(Variant::VECTOR3, vformat("point_%d/out", i));
pi.usage &= ~PROPERTY_USAGE_STORAGE;
p_list->push_back(pi);
@@ -2308,6 +2391,8 @@ void Curve3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_points"), &Curve3D::clear_points);
ClassDB::bind_method(D_METHOD("sample", "idx", "t"), &Curve3D::sample);
ClassDB::bind_method(D_METHOD("samplef", "fofs"), &Curve3D::samplef);
+ ClassDB::bind_method(D_METHOD("set_closed", "closed"), &Curve3D::set_closed);
+ ClassDB::bind_method(D_METHOD("is_closed"), &Curve3D::is_closed);
//ClassDB::bind_method(D_METHOD("bake","subdivs"),&Curve3D::bake,DEFVAL(10));
ClassDB::bind_method(D_METHOD("set_bake_interval", "distance"), &Curve3D::set_bake_interval);
ClassDB::bind_method(D_METHOD("get_bake_interval"), &Curve3D::get_bake_interval);
@@ -2329,6 +2414,8 @@ void Curve3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_get_data"), &Curve3D::_get_data);
ClassDB::bind_method(D_METHOD("_set_data", "data"), &Curve3D::_set_data);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "closed"), "set_closed", "is_closed");
+
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bake_interval", PROPERTY_HINT_RANGE, "0.01,512,0.01"), "set_bake_interval", "get_bake_interval");
ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
ADD_ARRAY_COUNT("Points", "point_count", "set_point_count", "get_point_count", "point_");
diff --git a/scene/resources/curve.h b/scene/resources/curve.h
index 6da337a93f..154d91e23b 100644
--- a/scene/resources/curve.h
+++ b/scene/resources/curve.h
@@ -264,6 +264,8 @@ class Curve3D : public Resource {
mutable Vector<size_t> points_in_cache;
#endif
+ bool closed = false;
+
mutable bool baked_cache_dirty = false;
mutable PackedVector3Array baked_point_cache;
mutable Vector<real_t> baked_tilt_cache;
@@ -330,6 +332,8 @@ public:
Vector3 sample(int p_index, real_t p_offset) const;
Vector3 samplef(real_t p_findex) const;
+ void set_closed(bool p_closed);
+ bool is_closed() const;
void set_bake_interval(real_t p_tolerance);
real_t get_bake_interval() const;
void set_up_vector_enabled(bool p_enable);
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index a4677d917d..ae70443e6a 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -1734,7 +1734,7 @@ Error FontFile::_load_bitmap_font(const String &p_path, List<String> *r_image_fi
while (true) {
String line = f->get_line();
- int delimiter = line.find(" ");
+ int delimiter = line.find_char(' ');
String type = line.substr(0, delimiter);
int pos = delimiter + 1;
HashMap<String, String> keys;
@@ -1744,7 +1744,7 @@ Error FontFile::_load_bitmap_font(const String &p_path, List<String> *r_image_fi
}
while (pos < line.size()) {
- int eq = line.find("=", pos);
+ int eq = line.find_char('=', pos);
if (eq == -1) {
break;
}
@@ -1752,14 +1752,14 @@ Error FontFile::_load_bitmap_font(const String &p_path, List<String> *r_image_fi
int end = -1;
String value;
if (line[eq + 1] == '"') {
- end = line.find("\"", eq + 2);
+ end = line.find_char('"', eq + 2);
if (end == -1) {
break;
}
value = line.substr(eq + 2, end - 1 - eq - 1);
pos = end + 1;
} else {
- end = line.find(" ", eq + 1);
+ end = line.find_char(' ', eq + 1);
if (end == -1) {
end = line.size();
}
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index b0353b4f2c..8c0e087902 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -1315,7 +1315,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
String sname = p_name;
if (sname.begins_with("surface_")) {
- int sl = sname.find("/");
+ int sl = sname.find_char('/');
if (sl == -1) {
return false;
}
@@ -1708,7 +1708,7 @@ bool ArrayMesh::_get(const StringName &p_name, Variant &r_ret) const {
String sname = p_name;
if (sname.begins_with("surface_")) {
- int sl = sname.find("/");
+ int sl = sname.find_char('/');
if (sl == -1) {
return false;
}
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 809a77a487..d7036fd6d5 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -822,10 +822,10 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
value = missing_resource_properties[E.name];
}
} else if (E.type == Variant::ARRAY && E.hint == PROPERTY_HINT_TYPE_STRING) {
- int hint_subtype_separator = E.hint_string.find(":");
+ int hint_subtype_separator = E.hint_string.find_char(':');
if (hint_subtype_separator >= 0) {
String subtype_string = E.hint_string.substr(0, hint_subtype_separator);
- int slash_pos = subtype_string.find("/");
+ int slash_pos = subtype_string.find_char('/');
PropertyHint subtype_hint = PropertyHint::PROPERTY_HINT_NONE;
if (slash_pos >= 0) {
subtype_hint = PropertyHint(subtype_string.get_slice("/", 1).to_int());
@@ -851,11 +851,11 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
}
}
} else if (E.type == Variant::DICTIONARY && E.hint == PROPERTY_HINT_TYPE_STRING) {
- int key_value_separator = E.hint_string.find(";");
+ int key_value_separator = E.hint_string.find_char(';');
if (key_value_separator >= 0) {
- int key_subtype_separator = E.hint_string.find(":");
+ int key_subtype_separator = E.hint_string.find_char(':');
String key_subtype_string = E.hint_string.substr(0, key_subtype_separator);
- int key_slash_pos = key_subtype_string.find("/");
+ int key_slash_pos = key_subtype_string.find_char('/');
PropertyHint key_subtype_hint = PropertyHint::PROPERTY_HINT_NONE;
if (key_slash_pos >= 0) {
key_subtype_hint = PropertyHint(key_subtype_string.get_slice("/", 1).to_int());
@@ -864,9 +864,9 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
Variant::Type key_subtype = Variant::Type(key_subtype_string.to_int());
bool convert_key = key_subtype == Variant::OBJECT && key_subtype_hint == PROPERTY_HINT_NODE_TYPE;
- int value_subtype_separator = E.hint_string.find(":", key_value_separator) - (key_value_separator + 1);
+ int value_subtype_separator = E.hint_string.find_char(':', key_value_separator) - (key_value_separator + 1);
String value_subtype_string = E.hint_string.substr(key_value_separator + 1, value_subtype_separator);
- int value_slash_pos = value_subtype_string.find("/");
+ int value_slash_pos = value_subtype_string.find_char('/');
PropertyHint value_subtype_hint = PropertyHint::PROPERTY_HINT_NONE;
if (value_slash_pos >= 0) {
value_subtype_hint = PropertyHint(value_subtype_string.get_slice("/", 1).to_int());
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 6e03fe25c9..03f0e107e4 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -1782,7 +1782,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
for (KeyValue<Ref<Resource>, String> &E : external_resources) {
String cached_id = E.key->get_id_for_path(local_path);
if (cached_id.is_empty() || cached_ids_found.has(cached_id)) {
- int sep_pos = E.value.find("_");
+ int sep_pos = E.value.find_char('_');
if (sep_pos != -1) {
E.value = E.value.substr(0, sep_pos + 1); // Keep the order found, for improved thread loading performance.
} else {
diff --git a/scene/resources/skeleton_profile.cpp b/scene/resources/skeleton_profile.cpp
index c2d77ec7ff..2a1b64078a 100644
--- a/scene/resources/skeleton_profile.cpp
+++ b/scene/resources/skeleton_profile.cpp
@@ -269,6 +269,14 @@ int SkeletonProfile::find_bone(const StringName &p_bone_name) const {
return -1;
}
+PackedStringArray SkeletonProfile::get_bone_names() {
+ PackedStringArray s;
+ for (const SkeletonProfileBone &bone : bones) {
+ s.push_back(bone.bone_name);
+ }
+ return s;
+}
+
StringName SkeletonProfile::get_bone_name(int p_bone_idx) const {
ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), StringName());
return bones[p_bone_idx].bone_name;
diff --git a/scene/resources/skeleton_profile.h b/scene/resources/skeleton_profile.h
index b5a3bce940..9361c6a9ce 100644
--- a/scene/resources/skeleton_profile.h
+++ b/scene/resources/skeleton_profile.h
@@ -97,6 +97,7 @@ public:
int find_bone(const StringName &p_bone_name) const;
+ PackedStringArray get_bone_names();
StringName get_bone_name(int p_bone_idx) const;
void set_bone_name(int p_bone_idx, const StringName &p_bone_name);
diff --git a/scene/resources/syntax_highlighter.cpp b/scene/resources/syntax_highlighter.cpp
index da90ba1ef2..4bc03a049a 100644
--- a/scene/resources/syntax_highlighter.cpp
+++ b/scene/resources/syntax_highlighter.cpp
@@ -205,7 +205,7 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting_impl(int p_line) {
if (end_key_length == 0 || color_regions[c].line_only || from + end_key_length > line_length) {
if (from + end_key_length > line_length && (color_regions[in_region].start_key == "\"" || color_regions[in_region].start_key == "\'")) {
// If it's key length and there is a '\', dont skip to highlight esc chars.
- if (str.find("\\", from) >= 0) {
+ if (str.find_char('\\', from) >= 0) {
break;
}
}
@@ -242,7 +242,7 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting_impl(int p_line) {
for (; from < line_length; from++) {
if (line_length - from < end_key_length) {
// Don't break if '\' to highlight esc chars.
- if (!is_string || str.find("\\", from) < 0) {
+ if (!is_string || str.find_char('\\', from) < 0) {
break;
}
}
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 847867fa4d..7c1adeac96 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -3167,6 +3167,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "projection_matrix", "PROJECTION_MATRIX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "screen_uv", "SCREEN_UV" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "specular", "SPECULAR_LIGHT" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 3db1ab9338..5350672a86 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -3243,6 +3243,29 @@ String VisualShaderNodeColorFunc::generate_code(Shader::Mode p_mode, VisualShade
code += " " + p_output_vars[0] + " = vec3(r, g, b);\n";
code += " }\n";
break;
+ case FUNC_LINEAR_TO_SRGB:
+ code += " {\n";
+ if (RenderingServer::get_singleton()->is_low_end()) {
+ code += " vec3 c = " + p_input_vars[0] + ";\n";
+ code += " " + p_output_vars[0] + " = max(vec3(1.055) * pow(c, vec3(0.416666667)) - vec3(0.055), vec3(0.0));\n";
+ } else {
+ code += " vec3 c = clamp(" + p_input_vars[0] + ", vec3(0.0), vec3(1.0));\n";
+ code += " const vec3 a = vec3(0.055f);\n";
+ code += " " + p_output_vars[0] + " = mix((vec3(1.0f) + a) * pow(c.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * c.rgb, lessThan(c.rgb, vec3(0.0031308f)));\n";
+ }
+ code += " }\n";
+ break;
+ case FUNC_SRGB_TO_LINEAR:
+ code += " {\n";
+ if (RenderingServer::get_singleton()->is_low_end()) {
+ code += " vec3 c = " + p_input_vars[0] + ";\n";
+ code += " " + p_output_vars[0] + " = c * (c * (c * 0.305306011 + 0.682171111) + 0.012522878);\n";
+ } else {
+ code += " vec3 c = " + p_input_vars[0] + ";\n";
+ code += " " + p_output_vars[0] + " = mix(pow((c.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), c.rgb * (1.0 / 12.92), lessThan(c.rgb, vec3(0.04045)));\n";
+ }
+ code += " }\n";
+ break;
default:
break;
}
@@ -3273,12 +3296,14 @@ void VisualShaderNodeColorFunc::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeColorFunc::set_function);
ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeColorFunc::get_function);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Grayscale,HSV2RGB,RGB2HSV,Sepia"), "set_function", "get_function");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Grayscale,HSV2RGB,RGB2HSV,Sepia,LinearToSRGB,SRGBToLinear"), "set_function", "get_function");
BIND_ENUM_CONSTANT(FUNC_GRAYSCALE);
BIND_ENUM_CONSTANT(FUNC_HSV2RGB);
BIND_ENUM_CONSTANT(FUNC_RGB2HSV);
BIND_ENUM_CONSTANT(FUNC_SEPIA);
+ BIND_ENUM_CONSTANT(FUNC_LINEAR_TO_SRGB);
+ BIND_ENUM_CONSTANT(FUNC_SRGB_TO_LINEAR);
BIND_ENUM_CONSTANT(FUNC_MAX);
}
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index 67dc8f7353..36b9560ced 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -1353,6 +1353,8 @@ public:
FUNC_HSV2RGB,
FUNC_RGB2HSV,
FUNC_SEPIA,
+ FUNC_LINEAR_TO_SRGB,
+ FUNC_SRGB_TO_LINEAR,
FUNC_MAX,
};
diff --git a/servers/rendering/dummy/storage/mesh_storage.h b/servers/rendering/dummy/storage/mesh_storage.h
index 855336c71f..556d58f411 100644
--- a/servers/rendering/dummy/storage/mesh_storage.h
+++ b/servers/rendering/dummy/storage/mesh_storage.h
@@ -170,6 +170,7 @@ public:
virtual Color _multimesh_instance_get_color(RID p_multimesh, int p_index) const override { return Color(); }
virtual Color _multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override { return Color(); }
virtual void _multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override;
+ virtual RID _multimesh_get_buffer_rd_rid(RID p_multimesh) const override { return RID(); }
virtual Vector<float> _multimesh_get_buffer(RID p_multimesh) const override;
virtual void _multimesh_set_visible_instances(RID p_multimesh, int p_visible) override {}
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index d01976acf2..22a9a4632d 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -278,6 +278,19 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
ci->children_order_dirty = false;
}
+ if (ci->use_parent_material && p_material_owner) {
+ ci->material_owner = p_material_owner;
+ } else {
+ p_material_owner = ci;
+ ci->material_owner = nullptr;
+ }
+
+ Color modulate = ci->modulate * p_modulate;
+
+ if (modulate.a < 0.007) {
+ return;
+ }
+
Rect2 rect = ci->get_rect();
if (ci->visibility_notifier) {
@@ -346,19 +359,6 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
}
global_rect.position += p_clip_rect.position;
- if (ci->use_parent_material && p_material_owner) {
- ci->material_owner = p_material_owner;
- } else {
- p_material_owner = ci;
- ci->material_owner = nullptr;
- }
-
- Color modulate(ci->modulate.r * p_modulate.r, ci->modulate.g * p_modulate.g, ci->modulate.b * p_modulate.b, ci->modulate.a * p_modulate.a);
-
- if (modulate.a < 0.007) {
- return;
- }
-
int child_item_count = ci->child_items.size();
Item **child_items = ci->child_items.ptrw();
diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp
index 63956a7918..83ec52ea75 100644
--- a/servers/rendering/renderer_rd/environment/sky.cpp
+++ b/servers/rendering/renderer_rd/environment/sky.cpp
@@ -972,26 +972,26 @@ SkyRD::~SkyRD() {
}
}
-void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const PagedArray<RID> &p_lights, RID p_camera_attributes, uint32_t p_view_count, const Projection *p_view_projections, const Vector3 *p_view_eye_offsets, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const Size2i p_screen_size, Vector2 p_jitter, RendererSceneRenderRD *p_scene_render) {
+void SkyRD::setup_sky(const RenderDataRD *p_render_data, const Size2i p_screen_size) {
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
- ERR_FAIL_COND(p_env.is_null());
+ ERR_FAIL_COND(p_render_data->environment.is_null());
- ERR_FAIL_COND(p_render_buffers.is_null());
+ ERR_FAIL_COND(p_render_data->render_buffers.is_null());
// make sure we support our view count
- ERR_FAIL_COND(p_view_count == 0);
- ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS);
+ ERR_FAIL_COND(p_render_data->scene_data->view_count == 0);
+ ERR_FAIL_COND(p_render_data->scene_data->view_count > RendererSceneRender::MAX_RENDER_VIEWS);
SkyMaterialData *material = nullptr;
- Sky *sky = get_sky(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
+ Sky *sky = get_sky(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_render_data->environment));
RID sky_material;
SkyShaderData *shader_data = nullptr;
if (sky) {
- sky_material = sky_get_material(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
+ sky_material = sky_get_material(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_render_data->environment));
if (sky_material.is_valid()) {
material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
@@ -1025,8 +1025,8 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con
update_dirty_skys();
}
- if (shader_data->uses_time && p_scene_render->time - sky->prev_time > 0.00001) {
- sky->prev_time = p_scene_render->time;
+ if (shader_data->uses_time && p_render_data->scene_data->time - sky->prev_time > 0.00001) {
+ sky->prev_time = p_render_data->scene_data->time;
sky->reflection.dirty = true;
RenderingServerDefault::redraw_request();
}
@@ -1041,29 +1041,30 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con
sky->reflection.dirty = true;
}
- if (!p_cam_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) {
- sky->prev_position = p_cam_transform.origin;
+ if (!p_render_data->scene_data->cam_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) {
+ sky->prev_position = p_render_data->scene_data->cam_transform.origin;
sky->reflection.dirty = true;
}
}
sky_scene_state.ubo.directional_light_count = 0;
if (shader_data->uses_light) {
+ const PagedArray<RID> &lights = *p_render_data->lights;
// Run through the list of lights in the scene and pick out the Directional Lights.
// This can't be done in RenderSceneRenderRD::_setup lights because that needs to be called
// after the depth prepass, but this runs before the depth prepass.
- for (int i = 0; i < (int)p_lights.size(); i++) {
- if (!light_storage->owns_light_instance(p_lights[i])) {
+ for (int i = 0; i < (int)lights.size(); i++) {
+ if (!light_storage->owns_light_instance(lights[i])) {
continue;
}
- RID base = light_storage->light_instance_get_base_light(p_lights[i]);
+ RID base = light_storage->light_instance_get_base_light(lights[i]);
ERR_CONTINUE(base.is_null());
RS::LightType type = light_storage->light_get_type(base);
if (type == RS::LIGHT_DIRECTIONAL && light_storage->light_directional_get_sky_mode(base) != RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_ONLY) {
SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[sky_scene_state.ubo.directional_light_count];
- Transform3D light_transform = light_storage->light_instance_get_base_transform(p_lights[i]);
+ Transform3D light_transform = light_storage->light_instance_get_base_transform(lights[i]);
Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
sky_light_data.direction[0] = world_direction.x;
@@ -1073,12 +1074,12 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con
float sign = light_storage->light_is_negative(base) ? -1 : 1;
sky_light_data.energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY);
- if (p_scene_render->is_using_physical_light_units()) {
+ if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) {
sky_light_data.energy *= light_storage->light_get_param(base, RS::LIGHT_PARAM_INTENSITY);
}
- if (p_camera_attributes.is_valid()) {
- sky_light_data.energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_camera_attributes);
+ if (p_render_data->camera_attributes.is_valid()) {
+ sky_light_data.energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
}
Color linear_col = light_storage->light_get_color(base).srgb_to_linear();
@@ -1149,43 +1150,48 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con
// Setup fog variables.
sky_scene_state.ubo.volumetric_fog_enabled = false;
- if (p_render_buffers.is_valid()) {
- if (p_render_buffers->has_custom_data(RB_SCOPE_FOG)) {
- Ref<RendererRD::Fog::VolumetricFog> fog = p_render_buffers->get_custom_data(RB_SCOPE_FOG);
- sky_scene_state.ubo.volumetric_fog_enabled = true;
-
- float fog_end = fog->length;
- if (fog_end > 0.0) {
- sky_scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end;
- } else {
- sky_scene_state.ubo.volumetric_fog_inv_length = 1.0;
- }
+ if (p_render_data->render_buffers->has_custom_data(RB_SCOPE_FOG)) {
+ Ref<RendererRD::Fog::VolumetricFog> fog = p_render_data->render_buffers->get_custom_data(RB_SCOPE_FOG);
+ sky_scene_state.ubo.volumetric_fog_enabled = true;
- float fog_detail_spread = fog->spread; // Reverse lookup.
- if (fog_detail_spread > 0.0) {
- sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread;
- } else {
- sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0;
- }
+ float fog_end = fog->length;
+ if (fog_end > 0.0) {
+ sky_scene_state.ubo.volumetric_fog_inv_length = 1.0 / fog_end;
+ } else {
+ sky_scene_state.ubo.volumetric_fog_inv_length = 1.0;
+ }
- sky_scene_state.fog_uniform_set = fog->sky_uniform_set;
+ float fog_detail_spread = fog->spread; // Reverse lookup.
+ if (fog_detail_spread > 0.0) {
+ sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0 / fog_detail_spread;
+ } else {
+ sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0;
}
+
+ sky_scene_state.fog_uniform_set = fog->sky_uniform_set;
}
+ sky_scene_state.view_count = p_render_data->scene_data->view_count;
+ sky_scene_state.cam_transform = p_render_data->scene_data->cam_transform;
+
Projection correction;
- correction.set_depth_correction(false, true);
- correction.add_jitter_offset(p_jitter);
+ correction.set_depth_correction(p_render_data->scene_data->flip_y, true);
+ correction.add_jitter_offset(p_render_data->scene_data->taa_jitter);
+
+ Projection projection = p_render_data->scene_data->cam_projection;
+ if (p_render_data->scene_data->cam_frustum) {
+ // We don't use a full projection matrix for the sky, this is enough to make up for it.
+ projection[2].y = -projection[2].y;
+ }
- sky_scene_state.view_count = p_view_count;
- sky_scene_state.cam_transform = p_cam_transform;
- sky_scene_state.cam_projection = correction * p_cam_projection; // We only use this when rendering a single view.
+ sky_scene_state.cam_projection = correction * projection;
// Our info in our UBO is only used if we're rendering stereo.
- for (uint32_t i = 0; i < p_view_count; i++) {
- Projection view_inv_projection = (correction * p_view_projections[i]).inverse();
- if (p_view_count > 1) {
+ for (uint32_t i = 0; i < p_render_data->scene_data->view_count; i++) {
+ Projection view_inv_projection = (correction * p_render_data->scene_data->view_projection[i]).inverse();
+ if (p_render_data->scene_data->view_count > 1) {
// Reprojection is used when we need to have things in combined space.
- RendererRD::MaterialStorage::store_camera(p_cam_projection * view_inv_projection, sky_scene_state.ubo.combined_reprojection[i]);
+ RendererRD::MaterialStorage::store_camera(p_render_data->scene_data->cam_projection * view_inv_projection, sky_scene_state.ubo.combined_reprojection[i]);
} else {
// This is unused so just reset to identity.
Projection ident;
@@ -1193,25 +1199,25 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con
}
RendererRD::MaterialStorage::store_camera(view_inv_projection, sky_scene_state.ubo.view_inv_projections[i]);
- sky_scene_state.ubo.view_eye_offsets[i][0] = p_view_eye_offsets[i].x;
- sky_scene_state.ubo.view_eye_offsets[i][1] = p_view_eye_offsets[i].y;
- sky_scene_state.ubo.view_eye_offsets[i][2] = p_view_eye_offsets[i].z;
+ sky_scene_state.ubo.view_eye_offsets[i][0] = p_render_data->scene_data->view_eye_offset[i].x;
+ sky_scene_state.ubo.view_eye_offsets[i][1] = p_render_data->scene_data->view_eye_offset[i].y;
+ sky_scene_state.ubo.view_eye_offsets[i][2] = p_render_data->scene_data->view_eye_offset[i].z;
sky_scene_state.ubo.view_eye_offsets[i][3] = 0.0;
}
- sky_scene_state.ubo.z_far = p_view_projections[0].get_z_far(); // Should be the same for all projection.
- sky_scene_state.ubo.fog_enabled = RendererSceneRenderRD::get_singleton()->environment_get_fog_enabled(p_env);
- sky_scene_state.ubo.fog_density = RendererSceneRenderRD::get_singleton()->environment_get_fog_density(p_env);
- sky_scene_state.ubo.fog_aerial_perspective = RendererSceneRenderRD::get_singleton()->environment_get_fog_aerial_perspective(p_env);
- Color fog_color = RendererSceneRenderRD::get_singleton()->environment_get_fog_light_color(p_env).srgb_to_linear();
- float fog_energy = RendererSceneRenderRD::get_singleton()->environment_get_fog_light_energy(p_env);
+ sky_scene_state.ubo.z_far = p_render_data->scene_data->view_projection[0].get_z_far(); // Should be the same for all projection.
+ sky_scene_state.ubo.fog_enabled = RendererSceneRenderRD::get_singleton()->environment_get_fog_enabled(p_render_data->environment);
+ sky_scene_state.ubo.fog_density = RendererSceneRenderRD::get_singleton()->environment_get_fog_density(p_render_data->environment);
+ sky_scene_state.ubo.fog_aerial_perspective = RendererSceneRenderRD::get_singleton()->environment_get_fog_aerial_perspective(p_render_data->environment);
+ Color fog_color = RendererSceneRenderRD::get_singleton()->environment_get_fog_light_color(p_render_data->environment).srgb_to_linear();
+ float fog_energy = RendererSceneRenderRD::get_singleton()->environment_get_fog_light_energy(p_render_data->environment);
sky_scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
sky_scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy;
sky_scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
- sky_scene_state.ubo.fog_sun_scatter = RendererSceneRenderRD::get_singleton()->environment_get_fog_sun_scatter(p_env);
+ sky_scene_state.ubo.fog_sun_scatter = RendererSceneRenderRD::get_singleton()->environment_get_fog_sun_scatter(p_render_data->environment);
- sky_scene_state.ubo.fog_sky_affect = RendererSceneRenderRD::get_singleton()->environment_get_fog_sky_affect(p_env);
- sky_scene_state.ubo.volumetric_fog_sky_affect = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_sky_affect(p_env);
+ sky_scene_state.ubo.fog_sky_affect = RendererSceneRenderRD::get_singleton()->environment_get_fog_sky_affect(p_render_data->environment);
+ sky_scene_state.ubo.volumetric_fog_sky_affect = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_sky_affect(p_render_data->environment);
RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo);
}
@@ -1292,7 +1298,7 @@ void SkyRD::update_radiance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers,
Projection cm;
cm.set_perspective(90, 1, 0.01, 10.0);
Projection correction;
- correction.set_depth_correction(true);
+ correction.set_depth_correction(false);
cm = correction * cm;
// Note, we ignore environment_get_sky_orientation here as this is applied when we do our lookup in our scene shader.
diff --git a/servers/rendering/renderer_rd/environment/sky.h b/servers/rendering/renderer_rd/environment/sky.h
index b146a416f9..cc753efa01 100644
--- a/servers/rendering/renderer_rd/environment/sky.h
+++ b/servers/rendering/renderer_rd/environment/sky.h
@@ -36,6 +36,7 @@
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/shaders/environment/sky.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
+#include "servers/rendering/renderer_rd/storage_rd/render_data_rd.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering/rendering_device.h"
#include "servers/rendering/shader_compiler.h"
@@ -294,7 +295,7 @@ public:
void set_texture_format(RD::DataFormat p_texture_format);
~SkyRD();
- void setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const PagedArray<RID> &p_lights, RID p_camera_attributes, uint32_t p_view_count, const Projection *p_view_projections, const Vector3 *p_view_eye_offsets, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const Size2i p_screen_size, Vector2 p_jitter, RendererSceneRenderRD *p_scene_render);
+ void setup_sky(const RenderDataRD *p_render_data, const Size2i p_screen_size);
void update_radiance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, const Vector3 &p_global_pos, double p_time, float p_luminance_multiplier = 1.0);
void update_res_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, double p_time, float p_luminance_multiplier = 1.0);
void draw_sky(RD::DrawListID p_draw_list, Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, RID p_fb, double p_time, float p_luminance_multiplier = 1.0);
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index eb73a9d7e6..b867e844c7 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -1957,22 +1957,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_command_begin_label("Setup Sky");
// Setup our sky render information for this frame/viewport
- if (is_reflection_probe) {
- Vector3 eye_offset;
- Projection correction;
- correction.set_depth_correction(true);
- Projection projection = correction * p_render_data->scene_data->cam_projection;
-
- sky.setup_sky(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, 1, &projection, &eye_offset, p_render_data->scene_data->cam_transform, projection, screen_size, Vector2(0.0f, 0.0f), this);
- } else {
- Projection projection = p_render_data->scene_data->cam_projection;
- if (p_render_data->scene_data->cam_frustum) {
- // Sky is drawn upside down, the frustum offset doesn't know the image is upside down so needs a flip.
- projection[2].y = -projection[2].y;
- }
-
- sky.setup_sky(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, p_render_data->scene_data->view_count, &projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, projection, screen_size, p_render_data->scene_data->taa_jitter, this);
- }
+ sky.setup_sky(p_render_data, screen_size);
sky_energy_multiplier *= bg_energy_multiplier;
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
index e1ed85779e..1f4058a121 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
@@ -273,7 +273,7 @@ public:
_FORCE_INLINE_ bool uses_shared_shadow_material() const {
bool backface_culling = cull_mode == CULL_BACK;
- return !uses_particle_trails && !writes_modelview_or_projection && !uses_vertex && !uses_position && !uses_discard && !uses_depth_prepass_alpha && !uses_alpha_clip && !uses_alpha_antialiasing && backface_culling && !uses_point_size && !uses_world_coordinates;
+ return !uses_particle_trails && !writes_modelview_or_projection && !uses_vertex && !uses_position && !uses_discard && !uses_depth_prepass_alpha && !uses_alpha_clip && !uses_alpha_antialiasing && backface_culling && !uses_point_size && !uses_world_coordinates && !wireframe;
}
virtual void set_code(const String &p_Code);
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index 5ad92bd211..411f0fe6a4 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -972,23 +972,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
RENDER_TIMESTAMP("Setup Sky");
RD::get_singleton()->draw_command_begin_label("Setup Sky");
- // Setup our sky render information for this frame/viewport
- if (is_reflection_probe) {
- Vector3 eye_offset;
- Projection correction;
- correction.set_depth_correction(true);
- Projection projection = correction * p_render_data->scene_data->cam_projection;
-
- sky.setup_sky(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, 1, &projection, &eye_offset, p_render_data->scene_data->cam_transform, projection, screen_size, Vector2(0.0f, 0.0f), this);
- } else {
- Projection projection = p_render_data->scene_data->cam_projection;
- if (p_render_data->scene_data->cam_frustum) {
- // Sky is drawn upside down, the frustum offset doesn't know the image is upside down so needs a flip.
- projection[2].y = -projection[2].y;
- }
-
- sky.setup_sky(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, p_render_data->scene_data->view_count, &projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, projection, screen_size, p_render_data->scene_data->taa_jitter, this);
- }
+ sky.setup_sky(p_render_data, screen_size);
sky_energy_multiplier *= bg_energy_multiplier;
@@ -2064,6 +2048,10 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
surf = surf->next;
}
}
+
+ if (p_render_list == RENDER_LIST_OPAQUE && lightmap_captures_used) {
+ RD::get_singleton()->buffer_update(scene_state.lightmap_capture_buffer, 0, sizeof(LightmapCaptureData) * lightmap_captures_used, scene_state.lightmap_captures);
+ }
}
void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
index f0afeebe79..e2549d1f00 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
@@ -243,7 +243,7 @@ public:
}
_FORCE_INLINE_ bool uses_shared_shadow_material() const {
- return !uses_particle_trails && !writes_modelview_or_projection && !uses_vertex && !uses_discard && !uses_depth_prepass_alpha && !uses_alpha_clip && !uses_alpha_antialiasing && !uses_world_coordinates;
+ return !uses_particle_trails && !writes_modelview_or_projection && !uses_vertex && !uses_discard && !uses_depth_prepass_alpha && !uses_alpha_clip && !uses_alpha_antialiasing && !uses_world_coordinates && !wireframe;
}
virtual void set_code(const String &p_Code);
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 0dcdb90948..165168cb29 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -666,6 +666,8 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
RD::get_singleton()->buffer_update(state.lights_uniform_buffer, 0, sizeof(LightUniform) * light_count, &state.light_uniforms[0]);
}
+ bool use_linear_colors = texture_storage->render_target_is_using_hdr(p_to_render_target);
+
{
//update canvas state uniform buffer
State::Buffer state_buffer;
@@ -684,7 +686,6 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
normal_transform.columns[2] = Vector2();
_update_transform_2d_to_mat4(normal_transform, state_buffer.canvas_normal_transform);
- bool use_linear_colors = texture_storage->render_target_is_using_hdr(p_to_render_target);
Color modulate = p_modulate;
if (use_linear_colors) {
modulate = p_modulate.srgb_to_linear();
@@ -722,6 +723,8 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
//print_line("w: " + itos(ssize.width) + " s: " + rtos(canvas_scale));
state_buffer.tex_to_sdf = 1.0 / ((canvas_scale.x + canvas_scale.y) * 0.5);
+ state_buffer.flags = use_linear_colors ? CANVAS_FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR : 0;
+
RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer);
}
@@ -752,8 +755,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
RenderTarget to_render_target;
to_render_target.render_target = p_to_render_target;
- bool use_linear_colors = texture_storage->render_target_is_using_hdr(p_to_render_target);
- to_render_target.base_flags = use_linear_colors ? FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR : 0;
+ to_render_target.use_linear_colors = use_linear_colors;
while (ci) {
if (ci->copy_back_buffer && canvas_group_owner == nullptr) {
@@ -2244,7 +2246,7 @@ RendererCanvasRenderRD::InstanceData *RendererCanvasRenderRD::new_instance_data(
instance_data->world[i] = p_world[i];
}
- instance_data->flags = p_base_flags | p_info->flags; // Reset on each command for safety, keep canvas texture binding config.
+ instance_data->flags = p_base_flags; // Reset on each command for safety.
instance_data->color_texture_pixel_size[0] = p_info->texpixel_size.width;
instance_data->color_texture_pixel_size[1] = p_info->texpixel_size.height;
@@ -2265,8 +2267,8 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
_update_transform_2d_to_mat2x3(base_transform, world);
Color base_color = p_item->final_modulate;
- bool use_linear_colors = bool(p_render_target.base_flags & FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR);
- uint32_t base_flags = p_render_target.base_flags;
+ bool use_linear_colors = p_render_target.use_linear_colors;
+ uint32_t base_flags = 0;
bool reclip = false;
@@ -2276,6 +2278,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
uint32_t lights[4] = { 0, 0, 0, 0 };
uint16_t light_count = 0;
+ uint16_t shadow_mask = 0;
{
Light *light = p_lights;
@@ -2285,6 +2288,10 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
uint32_t light_index = light->render_index_cache;
lights[light_count >> 2] |= light_index << ((light_count & 3) * 8);
+ if (p_item->light_mask & light->item_shadow_mask) {
+ shadow_mask |= 1 << light_count;
+ }
+
light_count++;
if (light_count == MAX_LIGHTS_PER_ITEM - 1) {
@@ -2294,7 +2301,8 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
light = light->next_ptr;
}
- base_flags |= light_count << FLAGS_LIGHT_COUNT_SHIFT;
+ base_flags |= light_count << INSTANCE_FLAGS_LIGHT_COUNT_SHIFT;
+ base_flags |= shadow_mask << INSTANCE_FLAGS_SHADOW_MASKED_SHIFT;
}
bool use_lighting = (light_count > 0 || using_directional_lights);
@@ -2323,6 +2331,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
// default variant
r_current_batch->shader_variant = SHADER_VARIANT_QUAD;
r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES;
+ r_current_batch->flags = 0;
}
RenderingServer::CanvasItemTextureRepeat rect_repeat = texture_repeat;
@@ -2378,20 +2387,18 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
if (rect->flags & CANVAS_RECT_FLIP_H) {
src_rect.size.x *= -1;
- instance_data->flags |= FLAGS_FLIP_H;
}
if (rect->flags & CANVAS_RECT_FLIP_V) {
src_rect.size.y *= -1;
- instance_data->flags |= FLAGS_FLIP_V;
}
if (rect->flags & CANVAS_RECT_TRANSPOSE) {
- instance_data->flags |= FLAGS_TRANSPOSE_RECT;
+ instance_data->flags |= INSTANCE_FLAGS_TRANSPOSE_RECT;
}
if (rect->flags & CANVAS_RECT_CLIP_UV) {
- instance_data->flags |= FLAGS_CLIP_RECT_UV;
+ instance_data->flags |= INSTANCE_FLAGS_CLIP_RECT_UV;
}
} else {
@@ -2410,13 +2417,13 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
}
if (has_msdf) {
- instance_data->flags |= FLAGS_USE_MSDF;
+ instance_data->flags |= INSTANCE_FLAGS_USE_MSDF;
instance_data->msdf[0] = rect->px_range; // Pixel range.
instance_data->msdf[1] = rect->outline; // Outline size.
instance_data->msdf[2] = 0.f; // Reserved.
instance_data->msdf[3] = 0.f; // Reserved.
} else if (rect->flags & CANVAS_RECT_LCD) {
- instance_data->flags |= FLAGS_USE_LCD;
+ instance_data->flags |= INSTANCE_FLAGS_USE_LCD;
}
instance_data->modulation[0] = modulated.r;
@@ -2447,6 +2454,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->has_blend = false;
r_current_batch->shader_variant = SHADER_VARIANT_NINEPATCH;
r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES;
+ r_current_batch->flags = 0;
}
TextureState tex_state(np->texture, texture_filter, texture_repeat, false, use_linear_colors);
@@ -2498,11 +2506,11 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
instance_data->dst_rect[2] = dst_rect.size.width;
instance_data->dst_rect[3] = dst_rect.size.height;
- instance_data->flags |= int(np->axis_x) << FLAGS_NINEPATCH_H_MODE_SHIFT;
- instance_data->flags |= int(np->axis_y) << FLAGS_NINEPATCH_V_MODE_SHIFT;
+ instance_data->flags |= int(np->axis_x) << INSTANCE_FLAGS_NINEPATCH_H_MODE_SHIFT;
+ instance_data->flags |= int(np->axis_y) << INSTANCE_FLAGS_NINEPATCH_V_MODE_SHIFT;
if (np->draw_center) {
- instance_data->flags |= FLAGS_NINEPACH_DRAW_CENTER;
+ instance_data->flags |= INSTANCE_FLAGS_NINEPACH_DRAW_CENTER;
}
instance_data->ninepatch_margins[0] = np->margin[SIDE_LEFT];
@@ -2522,6 +2530,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->command_type = Item::Command::TYPE_POLYGON;
r_current_batch->has_blend = false;
r_current_batch->command = c;
+ r_current_batch->flags = 0;
TextureState tex_state(polygon->texture, texture_filter, texture_repeat, false, use_linear_colors);
TextureInfo *tex_info = texture_info_map.getptr(tex_state);
@@ -2566,6 +2575,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->has_blend = false;
r_current_batch->command = c;
r_current_batch->primitive_points = primitive->point_count;
+ r_current_batch->flags = 0;
ERR_CONTINUE(primitive->point_count == 0 || primitive->point_count > 4);
@@ -2648,6 +2658,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->command = c;
r_current_batch->command_type = c->type;
r_current_batch->has_blend = false;
+ r_current_batch->flags = 0;
InstanceData *instance_data = nullptr;
@@ -2690,13 +2701,13 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
r_current_batch->tex_info = tex_info;
instance_data = new_instance_data(world, lights, base_flags, r_index, tex_info);
- instance_data->flags |= 1; // multimesh, trails disabled
+ r_current_batch->flags |= 1; // multimesh, trails disabled
if (mesh_storage->multimesh_uses_colors(mm->multimesh)) {
- instance_data->flags |= FLAGS_INSTANCING_HAS_COLORS;
+ r_current_batch->flags |= BATCH_FLAGS_INSTANCING_HAS_COLORS;
}
if (mesh_storage->multimesh_uses_custom_data(mm->multimesh)) {
- instance_data->flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;
+ r_current_batch->flags |= BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA;
}
} else if (c->type == Item::Command::TYPE_PARTICLES) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
@@ -2714,13 +2725,13 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
uint32_t divisor = 1;
r_current_batch->mesh_instance_count = particles_storage->particles_get_amount(pt->particles, divisor);
- instance_data->flags |= (divisor & FLAGS_INSTANCING_MASK);
+ r_current_batch->flags |= (divisor & BATCH_FLAGS_INSTANCING_MASK);
r_current_batch->mesh_instance_count /= divisor;
RID particles = pt->particles;
- instance_data->flags |= FLAGS_INSTANCING_HAS_COLORS;
- instance_data->flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;
+ r_current_batch->flags |= BATCH_FLAGS_INSTANCING_HAS_COLORS;
+ r_current_batch->flags |= BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA;
if (particles_storage->particles_has_collision(particles) && texture_storage->render_target_is_sdf_enabled(p_render_target.render_target)) {
// Pass collision information.
@@ -2806,6 +2817,7 @@ void RendererCanvasRenderRD::_record_item_commands(const Item *p_item, RenderTar
// default variant
r_current_batch->shader_variant = SHADER_VARIANT_QUAD;
r_current_batch->render_primitive = RD::RENDER_PRIMITIVE_TRIANGLES;
+ r_current_batch->flags = 0;
}
// 2: If the current batch has lighting, start a new batch.
@@ -2920,6 +2932,7 @@ void RendererCanvasRenderRD::_render_batch(RD::DrawListID p_draw_list, CanvasSha
PushConstant push_constant;
push_constant.base_instance_index = p_batch->start;
push_constant.specular_shininess = p_batch->tex_info->specular_shininess;
+ push_constant.batch_flags = p_batch->tex_info->flags | p_batch->flags;
RID pipeline;
PipelineKey pipeline_key;
@@ -3168,11 +3181,11 @@ void RendererCanvasRenderRD::_prepare_batch_texture_info(RID p_texture, TextureS
// cache values to be copied to instance data
if (info.specular_color.a < 0.999) {
- p_info->flags |= FLAGS_DEFAULT_SPECULAR_MAP_USED;
+ p_info->flags |= BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED;
}
if (info.use_normal) {
- p_info->flags |= FLAGS_DEFAULT_NORMAL_MAP_USED;
+ p_info->flags |= BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED;
}
uint8_t a = uint8_t(CLAMP(info.specular_color.a * 255.0, 0.0, 255.0));
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index 1bdc5076c5..e4f1779b09 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -65,31 +65,31 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
};
enum {
+ INSTANCE_FLAGS_LIGHT_COUNT_SHIFT = 0, // 4 bits for light count.
- FLAGS_INSTANCING_MASK = 0x7F,
- FLAGS_INSTANCING_HAS_COLORS = (1 << 7),
- FLAGS_INSTANCING_HAS_CUSTOM_DATA = (1 << 8),
+ INSTANCE_FLAGS_CLIP_RECT_UV = (1 << 4),
+ INSTANCE_FLAGS_TRANSPOSE_RECT = (1 << 5),
+ INSTANCE_FLAGS_USE_MSDF = (1 << 6),
+ INSTANCE_FLAGS_USE_LCD = (1 << 7),
- FLAGS_CLIP_RECT_UV = (1 << 9),
- FLAGS_TRANSPOSE_RECT = (1 << 10),
+ INSTANCE_FLAGS_NINEPACH_DRAW_CENTER = (1 << 8),
+ INSTANCE_FLAGS_NINEPATCH_H_MODE_SHIFT = 9,
+ INSTANCE_FLAGS_NINEPATCH_V_MODE_SHIFT = 11,
- FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR = (1 << 11),
-
- FLAGS_NINEPACH_DRAW_CENTER = (1 << 12),
-
- FLAGS_USE_SKELETON = (1 << 15),
- FLAGS_NINEPATCH_H_MODE_SHIFT = 16,
- FLAGS_NINEPATCH_V_MODE_SHIFT = 18,
- FLAGS_LIGHT_COUNT_SHIFT = 20,
+ INSTANCE_FLAGS_SHADOW_MASKED_SHIFT = 13, // 16 bits.
+ };
- FLAGS_DEFAULT_NORMAL_MAP_USED = (1 << 24),
- FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 25),
+ enum {
+ BATCH_FLAGS_INSTANCING_MASK = 0x7F,
+ BATCH_FLAGS_INSTANCING_HAS_COLORS = (1 << 7),
+ BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA = (1 << 8),
- FLAGS_USE_MSDF = (1 << 26),
- FLAGS_USE_LCD = (1 << 27),
+ BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED = (1 << 9),
+ BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 10),
+ };
- FLAGS_FLIP_H = (1 << 28),
- FLAGS_FLIP_V = (1 << 29),
+ enum {
+ CANVAS_FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR = (1 << 0),
};
enum {
@@ -370,7 +370,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
uint32_t base_instance_index;
ShaderSpecialization shader_specialization;
uint32_t specular_shininess;
- uint32_t pad;
+ uint32_t batch_flags;
};
// TextureState is used to determine when a new batch is required due to a change of texture state.
@@ -508,6 +508,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
uint32_t mesh_instance_count;
};
bool has_blend = false;
+ uint32_t flags = 0;
};
HashMap<TextureState, TextureInfo, HashableHasher<TextureState>> texture_info_map;
@@ -535,7 +536,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
uint32_t directional_light_count;
float tex_to_sdf;
- uint32_t pad1;
+ uint32_t flags;
uint32_t pad2;
};
@@ -596,9 +597,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
struct RenderTarget {
// Current render target for the canvas.
RID render_target;
- // The base flags for each InstanceData, derived from the render target.
- // Either FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR or 0
- uint32_t base_flags = 0;
+ bool use_linear_colors = false;
};
inline RID _get_pipeline_specialization_or_ubershader(CanvasShaderData *p_shader_data, PipelineKey &r_pipeline_key, PushConstant &r_push_constant, RID p_mesh_instance = RID(), void *p_surface = nullptr, uint32_t p_surface_index = 0, RID *r_vertex_array = nullptr);
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index f665bc24a4..b66aa71f6b 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -101,7 +101,7 @@ void main() {
vec2 vertex = vertex_attrib;
vec4 color = color_attrib;
- if (bool(draw_data.flags & FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR)) {
+ if (bool(canvas_data.flags & CANVAS_FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR)) {
color.rgb = srgb_to_linear(color.rgb);
}
color *= draw_data.modulation;
@@ -122,7 +122,7 @@ void main() {
vec2 vertex_base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
vec2 vertex_base = vertex_base_arr[gl_VertexIndex];
- vec2 uv = draw_data.src_rect.xy + abs(draw_data.src_rect.zw) * ((draw_data.flags & FLAGS_TRANSPOSE_RECT) != 0 ? vertex_base.yx : vertex_base.xy);
+ vec2 uv = draw_data.src_rect.xy + abs(draw_data.src_rect.zw) * ((draw_data.flags & INSTANCE_FLAGS_TRANSPOSE_RECT) != 0 ? vertex_base.yx : vertex_base.xy);
vec4 color = draw_data.modulation;
vec2 vertex = draw_data.dst_rect.xy + abs(draw_data.dst_rect.zw) * mix(vertex_base, vec2(1.0, 1.0) - vertex_base, lessThan(draw_data.src_rect.zw, vec2(0.0, 0.0)));
uvec4 bones = uvec4(0, 0, 0, 0);
@@ -133,7 +133,7 @@ void main() {
#ifdef USE_ATTRIBUTES
- uint instancing = draw_data.flags & FLAGS_INSTANCING_MASK;
+ uint instancing = params.batch_flags & BATCH_FLAGS_INSTANCING_MASK;
if (instancing > 1) {
// trails
@@ -172,19 +172,19 @@ void main() {
vertex = new_vertex;
color *= pcolor;
} else if (instancing == 1) {
- uint stride = 2 + bitfieldExtract(draw_data.flags, FLAGS_INSTANCING_HAS_COLORS_SHIFT, 1) + bitfieldExtract(draw_data.flags, FLAGS_INSTANCING_HAS_CUSTOM_DATA_SHIFT, 1);
+ uint stride = 2 + bitfieldExtract(params.batch_flags, BATCH_FLAGS_INSTANCING_HAS_COLORS_SHIFT, 1) + bitfieldExtract(params.batch_flags, BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA_SHIFT, 1);
uint offset = stride * gl_InstanceIndex;
mat4 matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
offset += 2;
- if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) {
+ if (bool(params.batch_flags & BATCH_FLAGS_INSTANCING_HAS_COLORS)) {
color *= transforms.data[offset];
offset += 1;
}
- if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
+ if (bool(params.batch_flags & BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
instance_custom = transforms.data[offset];
}
@@ -331,7 +331,7 @@ float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, flo
} else if (pixel >= draw_size - margin_end) {
return (tex_size - (draw_size - pixel)) * tex_pixel_size;
} else {
- draw_center -= 1 - int(bitfieldExtract(draw_data.flags, FLAGS_NINEPACH_DRAW_CENTER_SHIFT, 1));
+ draw_center -= 1 - int(bitfieldExtract(draw_data.flags, INSTANCE_FLAGS_NINEPATCH_DRAW_CENTER_SHIFT, 1));
// np_repeat is passed as uniform using NinePatchRect::AxisStretchMode enum.
if (np_repeat == 0) { // Stretch.
@@ -472,8 +472,8 @@ void main() {
int draw_center = 2;
uv = vec2(
- map_ninepatch_axis(pixel_size_interp.x, abs(draw_data.dst_rect.z), draw_data.color_texture_pixel_size.x, draw_data.ninepatch_margins.x, draw_data.ninepatch_margins.z, int(bitfieldExtract(draw_data.flags, FLAGS_NINEPATCH_H_MODE_SHIFT, 2)), draw_center),
- map_ninepatch_axis(pixel_size_interp.y, abs(draw_data.dst_rect.w), draw_data.color_texture_pixel_size.y, draw_data.ninepatch_margins.y, draw_data.ninepatch_margins.w, int(bitfieldExtract(draw_data.flags, FLAGS_NINEPATCH_V_MODE_SHIFT, 2)), draw_center));
+ map_ninepatch_axis(pixel_size_interp.x, abs(draw_data.dst_rect.z), draw_data.color_texture_pixel_size.x, draw_data.ninepatch_margins.x, draw_data.ninepatch_margins.z, int(bitfieldExtract(draw_data.flags, INSTANCE_FLAGS_NINEPATCH_H_MODE_SHIFT, 2)), draw_center),
+ map_ninepatch_axis(pixel_size_interp.y, abs(draw_data.dst_rect.w), draw_data.color_texture_pixel_size.y, draw_data.ninepatch_margins.y, draw_data.ninepatch_margins.w, int(bitfieldExtract(draw_data.flags, INSTANCE_FLAGS_NINEPATCH_V_MODE_SHIFT, 2)), draw_center));
if (draw_center == 0) {
color.a = 0.0;
@@ -482,7 +482,7 @@ void main() {
uv = uv * draw_data.src_rect.zw + draw_data.src_rect.xy; //apply region if needed
#endif
- if (bool(draw_data.flags & FLAGS_CLIP_RECT_UV)) {
+ if (bool(draw_data.flags & INSTANCE_FLAGS_CLIP_RECT_UV)) {
vec2 half_texpixel = draw_data.color_texture_pixel_size * 0.5;
uv = clamp(uv, draw_data.src_rect.xy + half_texpixel, draw_data.src_rect.xy + abs(draw_data.src_rect.zw) - half_texpixel);
}
@@ -490,7 +490,7 @@ void main() {
#endif
#ifndef USE_PRIMITIVE
- if (bool(draw_data.flags & FLAGS_USE_MSDF)) {
+ if (bool(draw_data.flags & INSTANCE_FLAGS_USE_MSDF)) {
float px_range = draw_data.ninepatch_margins.x;
float outline_thickness = draw_data.ninepatch_margins.y;
//float reserved1 = draw_data.ninepatch_margins.z;
@@ -510,7 +510,7 @@ void main() {
float a = clamp(d * px_size + 0.5, 0.0, 1.0);
color.a = a * color.a;
}
- } else if (bool(draw_data.flags & FLAGS_USE_LCD)) {
+ } else if (bool(draw_data.flags & INSTANCE_FLAGS_USE_LCD)) {
vec4 lcd_sample = texture(sampler2D(color_texture, texture_sampler), uv);
if (lcd_sample.a == 1.0) {
color.rgb = lcd_sample.rgb * color.a;
@@ -524,7 +524,7 @@ void main() {
color *= texture(sampler2D(color_texture, texture_sampler), uv);
}
- uint light_count = bitfieldExtract(draw_data.flags, FLAGS_LIGHT_COUNT_SHIFT, 4); //max 15 lights
+ uint light_count = draw_data.flags & 15u; //max 15 lights
bool using_light = (light_count + canvas_data.directional_light_count) > 0;
vec3 normal;
@@ -535,17 +535,15 @@ void main() {
bool normal_used = false;
#endif
- if (normal_used || (using_light && bool(draw_data.flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
+ if (normal_used || (using_light && bool(params.batch_flags & BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED))) {
normal.xy = texture(sampler2D(normal_texture, texture_sampler), uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0);
- if (bool(draw_data.flags & FLAGS_TRANSPOSE_RECT)) {
+
+#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
+ if (bool(draw_data.flags & INSTANCE_FLAGS_TRANSPOSE_RECT)) {
normal.xy = normal.yx;
}
- if (bool(draw_data.flags & FLAGS_FLIP_H)) {
- normal.x = -normal.x;
- }
- if (bool(draw_data.flags & FLAGS_FLIP_V)) {
- normal.y = -normal.y;
- }
+ normal.xy *= sign(draw_data.src_rect.zw);
+#endif
normal.z = sqrt(max(0.0, 1.0 - dot(normal.xy, normal.xy)));
normal_used = true;
} else {
@@ -561,7 +559,7 @@ void main() {
bool specular_shininess_used = false;
#endif
- if (specular_shininess_used || (using_light && normal_used && bool(draw_data.flags & FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
+ if (specular_shininess_used || (using_light && normal_used && bool(params.batch_flags & BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED))) {
specular_shininess = texture(sampler2D(specular_texture, texture_sampler), uv);
specular_shininess *= unpackUnorm4x8(params.specular_shininess);
specular_shininess_used = true;
@@ -632,7 +630,7 @@ void main() {
}
#endif
- if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
+ if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW) && bool(draw_data.flags & (INSTANCE_FLAGS_SHADOW_MASKED << i))) {
vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array.data[light_base].shadow_matrix[0], light_array.data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
vec4 shadow_uv = vec4(shadow_pos.x, light_array.data[light_base].shadow_y_ofs, shadow_pos.y * light_array.data[light_base].shadow_zfar_inv, 1.0);
@@ -692,7 +690,7 @@ void main() {
}
#endif
- if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW)) {
+ if (bool(light_array.data[light_base].flags & LIGHT_FLAGS_HAS_SHADOW) && bool(draw_data.flags & (INSTANCE_FLAGS_SHADOW_MASKED << i))) {
vec2 shadow_pos = (vec4(shadow_vertex, 0.0, 1.0) * mat4(light_array.data[light_base].shadow_matrix[0], light_array.data[light_base].shadow_matrix[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy; //multiply inverse given its transposed. Optimizer removes useless operations.
vec2 pos_norm = normalize(shadow_pos);
diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
index 84017a1fe1..da582ec1b4 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
@@ -1,36 +1,22 @@
-
#define MAX_LIGHTS_PER_ITEM 16
#define M_PI 3.14159265359
#define SDF_MAX_LENGTH 16384.0
-//1 means enabled, 2+ means trails in use
-#define FLAGS_INSTANCING_MASK 0x7F
-#define FLAGS_INSTANCING_HAS_COLORS_SHIFT 7
-#define FLAGS_INSTANCING_HAS_COLORS (1 << FLAGS_INSTANCING_HAS_COLORS_SHIFT)
-#define FLAGS_INSTANCING_HAS_CUSTOM_DATA_SHIFT 8
-#define FLAGS_INSTANCING_HAS_CUSTOM_DATA (1 << FLAGS_INSTANCING_HAS_CUSTOM_DATA_SHIFT)
-
-#define FLAGS_CLIP_RECT_UV (1 << 9)
-#define FLAGS_TRANSPOSE_RECT (1 << 10)
-#define FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR (1 << 11)
-#define FLAGS_NINEPACH_DRAW_CENTER_SHIFT 12
-#define FLAGS_NINEPACH_DRAW_CENTER (1 << FLAGS_NINEPACH_DRAW_CENTER_SHIFT)
-
-#define FLAGS_NINEPATCH_H_MODE_SHIFT 16
-#define FLAGS_NINEPATCH_V_MODE_SHIFT 18
-
-#define FLAGS_LIGHT_COUNT_SHIFT 20
+#define INSTANCE_FLAGS_LIGHT_COUNT_SHIFT 0 // 4 bits.
-#define FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 24)
-#define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 25)
+#define INSTANCE_FLAGS_CLIP_RECT_UV (1 << 4)
+#define INSTANCE_FLAGS_TRANSPOSE_RECT (1 << 5)
+#define INSTANCE_FLAGS_USE_MSDF (1 << 6)
+#define INSTANCE_FLAGS_USE_LCD (1 << 7)
-#define FLAGS_USE_MSDF (1 << 26)
-#define FLAGS_USE_LCD (1 << 27)
+#define INSTANCE_FLAGS_NINEPATCH_DRAW_CENTER_SHIFT 8
+#define INSTANCE_FLAGS_NINEPATCH_H_MODE_SHIFT 9
+#define INSTANCE_FLAGS_NINEPATCH_V_MODE_SHIFT 11
-#define FLAGS_FLIP_H (1 << 28)
-#define FLAGS_FLIP_V (1 << 29)
+#define INSTANCE_FLAGS_SHADOW_MASKED_SHIFT 13 // 16 bits.
+#define INSTANCE_FLAGS_SHADOW_MASKED (1 << INSTANCE_FLAGS_SHADOW_MASKED_SHIFT)
struct InstanceData {
vec2 world_x;
@@ -54,11 +40,21 @@ struct InstanceData {
uint lights[4];
};
+//1 means enabled, 2+ means trails in use
+#define BATCH_FLAGS_INSTANCING_MASK 0x7F
+#define BATCH_FLAGS_INSTANCING_HAS_COLORS_SHIFT 7
+#define BATCH_FLAGS_INSTANCING_HAS_COLORS (1 << BATCH_FLAGS_INSTANCING_HAS_COLORS_SHIFT)
+#define BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA_SHIFT 8
+#define BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA (1 << BATCH_FLAGS_INSTANCING_HAS_CUSTOM_DATA_SHIFT)
+
+#define BATCH_FLAGS_DEFAULT_NORMAL_MAP_USED (1 << 9)
+#define BATCH_FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 10)
+
layout(push_constant, std430) uniform Params {
uint base_instance_index; // base index to instance data
uint sc_packed_0;
uint specular_shininess;
- uint pad;
+ uint batch_flags;
}
params;
@@ -94,6 +90,8 @@ bool sc_use_lighting() {
/* SET0: Globals */
+#define CANVAS_FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR (1 << 0)
+
// The values passed per draw primitives are cached within it
layout(set = 0, binding = 1, std140) uniform CanvasData {
@@ -111,7 +109,7 @@ layout(set = 0, binding = 1, std140) uniform CanvasData {
uint directional_light_count;
float tex_to_sdf;
- uint pad1;
+ uint flags;
uint pad2;
}
canvas_data;
diff --git a/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl b/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl
index 158096d3c7..3d6eaab8e1 100644
--- a/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/decal_data_inc.glsl
@@ -1,4 +1,3 @@
-
struct DecalData {
highp mat4 xform; //to decal transform
highp vec3 inv_extents;
diff --git a/servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster_inc.glsl b/servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster_inc.glsl
index b8860f6518..fc45b1f827 100644
--- a/servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/luminance_reduce_raster_inc.glsl
@@ -1,4 +1,3 @@
-
layout(push_constant, std430) uniform PushConstant {
ivec2 source_size;
ivec2 dest_size;
diff --git a/servers/rendering/renderer_rd/shaders/environment/sky.glsl b/servers/rendering/renderer_rd/shaders/environment/sky.glsl
index cc1c40cad1..7bb2e0a539 100644
--- a/servers/rendering/renderer_rd/shaders/environment/sky.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/sky.glsl
@@ -189,7 +189,7 @@ void main() {
vec3 cube_normal;
#ifdef USE_MULTIVIEW
// In multiview our projection matrices will contain positional and rotational offsets that we need to properly unproject.
- vec4 unproject = vec4(uv_interp.x, -uv_interp.y, 0.0, 1.0); // unproject at the far plane
+ vec4 unproject = vec4(uv_interp.x, uv_interp.y, 0.0, 1.0); // unproject at the far plane
vec4 unprojected = sky_scene_data.view_inv_projections[ViewIndex] * unproject;
cube_normal = unprojected.xyz / unprojected.w;
@@ -198,7 +198,7 @@ void main() {
#else
cube_normal.z = -1.0;
cube_normal.x = (cube_normal.z * (-uv_interp.x - params.projection.x)) / params.projection.y;
- cube_normal.y = -(cube_normal.z * (-uv_interp.y - params.projection.z)) / params.projection.w;
+ cube_normal.y = -(cube_normal.z * (uv_interp.y - params.projection.z)) / params.projection.w;
#endif
cube_normal = mat3(params.orientation) * cube_normal;
cube_normal = normalize(cube_normal);
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
index 81d3d87a22..1e1b6d8937 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
@@ -2299,7 +2299,7 @@ void fragment_shader(in SceneData scene_data) {
#else
directional_lights.data[i].color * directional_lights.data[i].energy * tint,
#endif
- true, shadow, f0, orms, 1.0, albedo, alpha,
+ true, shadow, f0, orms, 1.0, albedo, alpha, screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -2373,7 +2373,7 @@ void fragment_shader(in SceneData scene_data) {
shadow = blur_shadow(shadow);
- light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha,
+ light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -2445,7 +2445,7 @@ void fragment_shader(in SceneData scene_data) {
shadow = blur_shadow(shadow);
- light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha,
+ light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
index 404f658fa6..0cb34557ea 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
@@ -434,12 +434,12 @@ void main() {
vertex_interp = vertex;
#ifdef NORMAL_USED
- normal_interp = normal;
+ normal_interp = normalize(normal);
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
- tangent_interp = tangent;
- binormal_interp = binormal;
+ tangent_interp = normalize(tangent);
+ binormal_interp = normalize(binormal);
#endif
// VERTEX LIGHTING
@@ -456,13 +456,13 @@ void main() {
uvec2 omni_light_indices = instances.data[draw_call.instance_index].omni_lights;
for (uint i = 0; i < sc_omni_lights(); i++) {
uint light_index = (i > 3) ? ((omni_light_indices.y >> ((i - 4) * 8)) & 0xFF) : ((omni_light_indices.x >> (i * 8)) & 0xFF);
- light_process_omni_vertex(light_index, vertex, view, normal, roughness, diffuse_light_interp.rgb, specular_light_interp.rgb);
+ light_process_omni_vertex(light_index, vertex, view, normal_interp, roughness, diffuse_light_interp.rgb, specular_light_interp.rgb);
}
uvec2 spot_light_indices = instances.data[draw_call.instance_index].spot_lights;
for (uint i = 0; i < sc_spot_lights(); i++) {
uint light_index = (i > 3) ? ((spot_light_indices.y >> ((i - 4) * 8)) & 0xFF) : ((spot_light_indices.x >> (i * 8)) & 0xFF);
- light_process_spot_vertex(light_index, vertex, view, normal, roughness, diffuse_light_interp.rgb, specular_light_interp.rgb);
+ light_process_spot_vertex(light_index, vertex, view, normal_interp, roughness, diffuse_light_interp.rgb, specular_light_interp.rgb);
}
if (sc_directional_lights() > 0) {
@@ -479,13 +479,13 @@ void main() {
continue; // Statically baked light and object uses lightmap, skip.
}
if (i == 0) {
- light_compute_vertex(normal, directional_lights.data[0].direction, view,
+ light_compute_vertex(normal_interp, directional_lights.data[0].direction, view,
directional_lights.data[0].color * directional_lights.data[0].energy,
true, roughness,
directional_diffuse,
directional_specular);
} else {
- light_compute_vertex(normal, directional_lights.data[i].direction, view,
+ light_compute_vertex(normal_interp, directional_lights.data[i].direction, view,
directional_lights.data[i].color * directional_lights.data[i].energy,
true, roughness,
diffuse_light_interp.rgb,
@@ -1591,7 +1591,7 @@ void main() {
light_compute(normal, directional_lights.data[i].direction, view, size_A,
directional_lights.data[i].color * directional_lights.data[i].energy * tint,
- true, shadow, f0, orms, 1.0, albedo, alpha,
+ true, shadow, f0, orms, 1.0, albedo, alpha, screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -1628,7 +1628,7 @@ void main() {
shadow = blur_shadow(shadow);
// Fragment lighting
- light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha,
+ light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -1661,7 +1661,7 @@ void main() {
shadow = blur_shadow(shadow);
- light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha,
+ light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
index a1a185d0fd..1e8fc7eab4 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
@@ -39,7 +39,7 @@ vec3 F0(float metallic, float specular, vec3 albedo) {
return mix(vec3(dielectric), albedo, vec3(metallic));
}
-void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_directional, float attenuation, vec3 f0, uint orms, float specular_amount, vec3 albedo, inout float alpha,
+void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_directional, float attenuation, vec3 f0, uint orms, float specular_amount, vec3 albedo, inout float alpha, vec2 screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
@@ -547,7 +547,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal, float taa_fr
return 1.0;
}
-void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha,
+void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha, vec2 screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
@@ -675,7 +675,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
light_attenuation *= shadow;
- light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount, albedo, alpha,
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount, albedo, alpha, screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
@@ -793,7 +793,7 @@ vec2 normal_to_panorama(vec3 n) {
return panorama_coords;
}
-void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha,
+void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha, vec2 screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
vec3 backlight,
#endif
@@ -884,7 +884,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
}
light_attenuation *= shadow;
- light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount, albedo, alpha,
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount, albedo, alpha, screen_uv,
#ifdef LIGHT_BACKLIGHT_USED
backlight,
#endif
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
index 0d468ad1e3..7537e70235 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
@@ -1997,6 +1997,12 @@ void MeshStorage::_multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_
}
}
+RID MeshStorage::_multimesh_get_buffer_rd_rid(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_NULL_V(multimesh, RID());
+ return multimesh->buffer;
+}
+
Vector<float> MeshStorage::_multimesh_get_buffer(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_NULL_V(multimesh, Vector<float>());
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
index c14c2945bd..11962b05f4 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
@@ -651,6 +651,7 @@ public:
virtual Color _multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override;
virtual void _multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) override;
+ virtual RID _multimesh_get_buffer_rd_rid(RID p_multimesh) const override;
virtual Vector<float> _multimesh_get_buffer(RID p_multimesh) const override;
virtual void _multimesh_set_visible_instances(RID p_multimesh, int p_visible) override;
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index 11ca7de44f..2420a24261 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -3017,7 +3017,8 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
cull_data.cull->lock.lock();
RSG::particles_storage->particles_request_process(idata.base_rid);
cull_data.cull->lock.unlock();
- RSG::particles_storage->particles_set_view_axis(idata.base_rid, -cull_data.cam_transform.basis.get_column(2).normalized(), cull_data.cam_transform.basis.get_column(1).normalized());
+
+ RS::get_singleton()->call_on_render_thread(callable_mp_static(&RendererSceneCull::_scene_particles_set_view_axis).bind(idata.base_rid, -cull_data.cam_transform.basis.get_column(2).normalized(), cull_data.cam_transform.basis.get_column(1).normalized()));
//particles visible? request redraw
RenderingServerDefault::redraw_request();
}
@@ -3192,6 +3193,10 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
}
}
+void RendererSceneCull::_scene_particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) {
+ RSG::particles_storage->particles_set_view_axis(p_particles, p_axis, p_up_axis);
+}
+
void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_camera_data, const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, RID p_force_camera_attributes, RID p_compositor, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, bool p_using_shadows, RenderingMethod::RenderInfo *r_render_info) {
Instance *render_reflection_probe = instance_owner.get_or_null(p_reflection_probe); //if null, not rendering to it
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h
index 82523fd4ef..8161f50a35 100644
--- a/servers/rendering/renderer_scene_cull.h
+++ b/servers/rendering/renderer_scene_cull.h
@@ -1184,9 +1184,11 @@ public:
void _scene_cull_threaded(uint32_t p_thread, CullData *cull_data);
void _scene_cull(CullData &cull_data, InstanceCullResult &cull_result, uint64_t p_from, uint64_t p_to);
+ static void _scene_particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis);
_FORCE_INLINE_ bool _visibility_parent_check(const CullData &p_cull_data, const InstanceData &p_instance_data);
bool _render_reflection_probe_step(Instance *p_instance, int p_step);
+
void _render_scene(const RendererSceneRender::CameraData *p_camera_data, const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, RID p_force_camera_attributes, RID p_compositor, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, bool p_using_shadows = true, RenderInfo *r_render_info = nullptr);
void render_empty_scene(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_scenario, RID p_shadow_atlas);
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index cc67873b24..e9fa38475e 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -946,6 +946,7 @@ RID RenderingDevice::texture_create_shared(const TextureView &p_view, RID p_with
RDG::ResourceTracker *tracker = RDG::resource_tracker_create();
tracker->texture_driver_id = texture.shared_fallback->texture;
+ tracker->texture_size = Size2i(texture.width, texture.height);
tracker->texture_subresources = texture.barrier_range();
tracker->texture_usage = alias_format.usage_bits;
tracker->reference_count = 1;
@@ -1125,6 +1126,7 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view,
RDG::ResourceTracker *tracker = RDG::resource_tracker_create();
tracker->texture_driver_id = texture.shared_fallback->texture;
+ tracker->texture_size = Size2i(texture.width, texture.height);
tracker->texture_subresources = slice_range;
tracker->texture_usage = slice_format.usage_bits;
tracker->reference_count = 1;
@@ -5272,14 +5274,13 @@ void RenderingDevice::_wait_for_transfer_worker(TransferWorker *p_transfer_worke
p_transfer_worker->operations_processed = p_transfer_worker->operations_submitted;
}
- if (!p_transfer_worker->texture_barriers.is_empty()) {
- MutexLock transfer_worker_lock(transfer_worker_pool_mutex);
- _flush_barriers_for_transfer_worker(p_transfer_worker);
- }
+ _flush_barriers_for_transfer_worker(p_transfer_worker);
}
void RenderingDevice::_flush_barriers_for_transfer_worker(TransferWorker *p_transfer_worker) {
+ // Caller must have already acquired the mutex for the worker.
if (!p_transfer_worker->texture_barriers.is_empty()) {
+ MutexLock transfer_worker_lock(transfer_worker_pool_texture_barriers_mutex);
for (uint32_t i = 0; i < p_transfer_worker->texture_barriers.size(); i++) {
transfer_worker_pool_texture_barriers.push_back(p_transfer_worker->texture_barriers[i]);
}
@@ -5352,8 +5353,11 @@ void RenderingDevice::_submit_transfer_workers(RDD::CommandBufferID p_draw_comma
}
}
}
+}
- if (p_draw_command_buffer && !transfer_worker_pool_texture_barriers.is_empty()) {
+void RenderingDevice::_submit_transfer_barriers(RDD::CommandBufferID p_draw_command_buffer) {
+ MutexLock transfer_worker_lock(transfer_worker_pool_texture_barriers_mutex);
+ if (!transfer_worker_pool_texture_barriers.is_empty()) {
driver->command_pipeline_barrier(p_draw_command_buffer, RDD::PIPELINE_STAGE_COPY_BIT, RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, {}, {}, transfer_worker_pool_texture_barriers);
transfer_worker_pool_texture_barriers.clear();
}
@@ -5413,6 +5417,7 @@ bool RenderingDevice::_texture_make_mutable(Texture *p_texture, RID p_texture_id
draw_tracker = RDG::resource_tracker_create();
draw_tracker->parent = owner_texture->draw_tracker;
draw_tracker->texture_driver_id = p_texture->driver_id;
+ draw_tracker->texture_size = Size2i(p_texture->width, p_texture->height);
draw_tracker->texture_subresources = p_texture->barrier_range();
draw_tracker->texture_usage = p_texture->usage_flags;
draw_tracker->texture_slice_or_dirty_rect = p_texture->slice_rect;
@@ -5435,6 +5440,7 @@ bool RenderingDevice::_texture_make_mutable(Texture *p_texture, RID p_texture_id
// Regular texture.
p_texture->draw_tracker = RDG::resource_tracker_create();
p_texture->draw_tracker->texture_driver_id = p_texture->driver_id;
+ p_texture->draw_tracker->texture_size = Size2i(p_texture->width, p_texture->height);
p_texture->draw_tracker->texture_subresources = p_texture->barrier_range();
p_texture->draw_tracker->texture_usage = p_texture->usage_flags;
p_texture->draw_tracker->reference_count = 1;
@@ -5953,6 +5959,7 @@ void RenderingDevice::_end_frame() {
// The command buffer must be copied into a stack variable as the driver workarounds can change the command buffer in use.
RDD::CommandBufferID command_buffer = frames[frame].command_buffer;
_submit_transfer_workers(command_buffer);
+ _submit_transfer_barriers(command_buffer);
draw_graph.end(RENDER_GRAPH_REORDER, RENDER_GRAPH_FULL_BARRIERS, command_buffer, frames[frame].command_buffer_pool);
driver->command_buffer_end(command_buffer);
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 9939df976f..ccfe51043b 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -1285,6 +1285,7 @@ private:
LocalVector<uint32_t> transfer_worker_pool_available_list;
LocalVector<RDD::TextureBarrier> transfer_worker_pool_texture_barriers;
BinaryMutex transfer_worker_pool_mutex;
+ BinaryMutex transfer_worker_pool_texture_barriers_mutex;
ConditionVariable transfer_worker_pool_condition;
TransferWorker *_acquire_transfer_worker(uint32_t p_transfer_size, uint32_t p_required_align, uint32_t &r_staging_offset);
@@ -1299,6 +1300,7 @@ private:
void _check_transfer_worker_vertex_array(VertexArray *p_vertex_array);
void _check_transfer_worker_index_array(IndexArray *p_index_array);
void _submit_transfer_workers(RDD::CommandBufferID p_draw_command_buffer = RDD::CommandBufferID());
+ void _submit_transfer_barriers(RDD::CommandBufferID p_draw_command_buffer);
void _wait_for_transfer_workers();
void _free_transfer_workers();
diff --git a/servers/rendering/rendering_device_graph.cpp b/servers/rendering/rendering_device_graph.cpp
index ec2f336f3c..ebfe328393 100644
--- a/servers/rendering/rendering_device_graph.cpp
+++ b/servers/rendering/rendering_device_graph.cpp
@@ -159,6 +159,23 @@ bool RenderingDeviceGraph::_check_command_intersection(ResourceTracker *p_resour
return previous_draw_list_command.region.intersects(current_draw_list_command.region);
}
+bool RenderingDeviceGraph::_check_command_partial_coverage(ResourceTracker *p_resource_tracker, int32_t p_command_index) const {
+ if (p_resource_tracker->usage != RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE && p_resource_tracker->usage != RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE) {
+ // We don't check for partial coverage in usages that aren't attachment writes.
+ return true;
+ }
+
+ const uint32_t command_data_offset = command_data_offsets[p_command_index];
+ const RecordedDrawListCommand &draw_list_command = *reinterpret_cast<const RecordedDrawListCommand *>(&command_data[command_data_offset]);
+ if (draw_list_command.type != RecordedCommand::TYPE_DRAW_LIST) {
+ // We don't check for partial coverage on commands that aren't draw lists.
+ return false;
+ }
+
+ Rect2i texture_region(Point2i(0, 0), p_resource_tracker->texture_size);
+ return !draw_list_command.region.encloses(texture_region);
+}
+
int32_t RenderingDeviceGraph::_add_to_command_list(int32_t p_command_index, int32_t p_list_index) {
DEV_ASSERT(p_command_index < int32_t(command_count));
DEV_ASSERT(p_list_index < int32_t(command_list_nodes.size()));
@@ -194,7 +211,7 @@ int32_t RenderingDeviceGraph::_add_to_slice_read_list(int32_t p_command_index, R
return next_index;
}
-int32_t RenderingDeviceGraph::_add_to_write_list(int32_t p_command_index, Rect2i p_subresources, int32_t p_list_index) {
+int32_t RenderingDeviceGraph::_add_to_write_list(int32_t p_command_index, Rect2i p_subresources, int32_t p_list_index, bool p_partial_coverage) {
DEV_ASSERT(p_command_index < int32_t(command_count));
DEV_ASSERT(p_list_index < int32_t(write_slice_list_nodes.size()));
@@ -205,6 +222,7 @@ int32_t RenderingDeviceGraph::_add_to_write_list(int32_t p_command_index, Rect2i
new_node.command_index = p_command_index;
new_node.next_list_index = p_list_index;
new_node.subresources = p_subresources;
+ new_node.partial_coverage = p_partial_coverage;
return next_index;
}
@@ -471,7 +489,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
resource_tracker->usage = new_resource_usage;
}
- bool command_intersection_failed = false;
+ bool write_usage_has_partial_coverage = !different_usage && _check_command_partial_coverage(resource_tracker, p_command_index);
if (search_tracker->write_command_or_list_index >= 0) {
if (search_tracker->write_command_list_enabled) {
// Make this command adjacent to any commands that wrote to this resource and intersect with the slice if it applies.
@@ -483,11 +501,11 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
if (!resource_has_parent || search_tracker_rect.intersects(write_list_node.subresources)) {
if (write_list_node.command_index == p_command_index) {
ERR_FAIL_COND_MSG(!resource_has_parent, "Command can't have itself as a dependency.");
- } else if (_check_command_intersection(resource_tracker, write_list_node.command_index, p_command_index)) {
+ } else if (!write_list_node.partial_coverage || _check_command_intersection(resource_tracker, write_list_node.command_index, p_command_index)) {
// Command is dependent on this command. Add this command to the adjacency list of the write command.
_add_adjacent_command(write_list_node.command_index, p_command_index, r_command);
- if (resource_has_parent && write_usage && search_tracker_rect.encloses(write_list_node.subresources)) {
+ if (resource_has_parent && write_usage && search_tracker_rect.encloses(write_list_node.subresources) && !write_usage_has_partial_coverage) {
// Eliminate redundant writes from the list.
if (previous_write_list_index >= 0) {
RecordedSliceListNode &previous_list_node = write_slice_list_nodes[previous_write_list_index];
@@ -499,8 +517,6 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
write_list_index = write_list_node.next_list_index;
continue;
}
- } else {
- command_intersection_failed = true;
}
}
@@ -511,24 +527,23 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
// The index is just the latest command index that wrote to the resource.
if (search_tracker->write_command_or_list_index == p_command_index) {
ERR_FAIL_MSG("Command can't have itself as a dependency.");
- } else if (_check_command_intersection(resource_tracker, search_tracker->write_command_or_list_index, p_command_index)) {
- _add_adjacent_command(search_tracker->write_command_or_list_index, p_command_index, r_command);
} else {
- command_intersection_failed = true;
+ _add_adjacent_command(search_tracker->write_command_or_list_index, p_command_index, r_command);
}
}
}
if (write_usage) {
- if (resource_has_parent || command_intersection_failed) {
+ bool use_write_list = resource_has_parent || write_usage_has_partial_coverage;
+ if (use_write_list) {
if (!search_tracker->write_command_list_enabled && search_tracker->write_command_or_list_index >= 0) {
// Write command list was not being used but there was a write command recorded. Add a new node with the entire parent resource's subresources and the recorded command index to the list.
const RDD::TextureSubresourceRange &tracker_subresources = search_tracker->texture_subresources;
Rect2i tracker_rect(tracker_subresources.base_mipmap, tracker_subresources.base_layer, tracker_subresources.mipmap_count, tracker_subresources.layer_count);
- search_tracker->write_command_or_list_index = _add_to_write_list(search_tracker->write_command_or_list_index, tracker_rect, -1);
+ search_tracker->write_command_or_list_index = _add_to_write_list(search_tracker->write_command_or_list_index, tracker_rect, -1, false);
}
- search_tracker->write_command_or_list_index = _add_to_write_list(p_command_index, search_tracker_rect, search_tracker->write_command_or_list_index);
+ search_tracker->write_command_or_list_index = _add_to_write_list(p_command_index, search_tracker_rect, search_tracker->write_command_or_list_index, write_usage_has_partial_coverage);
search_tracker->write_command_list_enabled = true;
} else {
search_tracker->write_command_or_list_index = p_command_index;
@@ -553,7 +568,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
read_full_command_list_index = read_full_next_index;
}
- if (!resource_has_parent) {
+ if (!use_write_list) {
// Clear the full list if this resource is not a slice.
search_tracker->read_full_command_list_index = -1;
}
@@ -563,7 +578,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
int32_t read_slice_command_list_index = search_tracker->read_slice_command_list_index;
while (read_slice_command_list_index >= 0) {
const RecordedSliceListNode &read_list_node = read_slice_list_nodes[read_slice_command_list_index];
- if (!resource_has_parent || search_tracker_rect.encloses(read_list_node.subresources)) {
+ if (!use_write_list || search_tracker_rect.encloses(read_list_node.subresources)) {
if (previous_slice_command_list_index >= 0) {
// Erase this element and connect the previous one to the next element.
read_slice_list_nodes[previous_slice_command_list_index].next_list_index = read_list_node.next_list_index;
diff --git a/servers/rendering/rendering_device_graph.h b/servers/rendering/rendering_device_graph.h
index 9ddd70bc80..f7d9027147 100644
--- a/servers/rendering/rendering_device_graph.h
+++ b/servers/rendering/rendering_device_graph.h
@@ -167,6 +167,7 @@ public:
RDD::BufferID buffer_driver_id;
RDD::TextureID texture_driver_id;
RDD::TextureSubresourceRange texture_subresources;
+ Size2i texture_size;
uint32_t texture_usage = 0;
int32_t texture_slice_command_index = -1;
ResourceTracker *parent = nullptr;
@@ -271,6 +272,7 @@ private:
int32_t command_index = -1;
int32_t next_list_index = -1;
Rect2i subresources;
+ bool partial_coverage = false;
};
struct RecordedBufferClearCommand : RecordedCommand {
@@ -650,10 +652,11 @@ private:
static RDD::TextureLayout _usage_to_image_layout(ResourceUsage p_usage);
static RDD::BarrierAccessBits _usage_to_access_bits(ResourceUsage p_usage);
bool _check_command_intersection(ResourceTracker *p_resource_tracker, int32_t p_previous_command_index, int32_t p_command_index) const;
+ bool _check_command_partial_coverage(ResourceTracker *p_resource_tracker, int32_t p_command_index) const;
int32_t _add_to_command_list(int32_t p_command_index, int32_t p_list_index);
void _add_adjacent_command(int32_t p_previous_command_index, int32_t p_command_index, RecordedCommand *r_command);
int32_t _add_to_slice_read_list(int32_t p_command_index, Rect2i p_subresources, int32_t p_list_index);
- int32_t _add_to_write_list(int32_t p_command_index, Rect2i p_subresources, int32_t p_list_index);
+ int32_t _add_to_write_list(int32_t p_command_index, Rect2i p_subresources, int32_t p_list_index, bool p_partial_coverage);
RecordedCommand *_allocate_command(uint32_t p_command_size, int32_t &r_command_index);
DrawListInstruction *_allocate_draw_list_instruction(uint32_t p_instruction_size);
ComputeListInstruction *_allocate_compute_list_instruction(uint32_t p_instruction_size);
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 5c3ee513c7..29b1e163c7 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -403,6 +403,7 @@ public:
FUNC2RC(Color, multimesh_instance_get_custom_data, RID, int)
FUNC2(multimesh_set_buffer, RID, const Vector<float> &)
+ FUNC1RC(RID, multimesh_get_buffer_rd_rid, RID)
FUNC1RC(Vector<float>, multimesh_get_buffer, RID)
FUNC3(multimesh_set_buffer_interpolated, RID, const Vector<float> &, const Vector<float> &)
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index 821009f07c..4b71007ebf 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -201,6 +201,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["DIFFUSE_LIGHT"] = ShaderLanguage::TYPE_VEC3;
shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["SPECULAR_LIGHT"] = ShaderLanguage::TYPE_VEC3;
shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["ALPHA"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_SPATIAL].functions["light"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_SPATIAL].functions["light"].can_discard = true;
shader_modes[RS::SHADER_SPATIAL].functions["light"].main_function = true;
diff --git a/servers/rendering/storage/mesh_storage.cpp b/servers/rendering/storage/mesh_storage.cpp
index 6680920c98..4a6746e6c9 100644
--- a/servers/rendering/storage/mesh_storage.cpp
+++ b/servers/rendering/storage/mesh_storage.cpp
@@ -223,6 +223,10 @@ void RendererMeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<flo
_multimesh_set_buffer(p_multimesh, p_buffer);
}
+RID RendererMeshStorage::multimesh_get_buffer_rd_rid(RID p_multimesh) const {
+ return _multimesh_get_buffer_rd_rid(p_multimesh);
+}
+
Vector<float> RendererMeshStorage::multimesh_get_buffer(RID p_multimesh) const {
return _multimesh_get_buffer(p_multimesh);
}
diff --git a/servers/rendering/storage/mesh_storage.h b/servers/rendering/storage/mesh_storage.h
index 5e3a4738e6..6a8b385a69 100644
--- a/servers/rendering/storage/mesh_storage.h
+++ b/servers/rendering/storage/mesh_storage.h
@@ -141,6 +141,7 @@ public:
virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const;
virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer);
+ virtual RID multimesh_get_buffer_rd_rid(RID p_multimesh) const;
virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const;
virtual void multimesh_set_buffer_interpolated(RID p_multimesh, const Vector<float> &p_buffer, const Vector<float> &p_buffer_prev);
@@ -178,6 +179,7 @@ public:
virtual Color _multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0;
virtual void _multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) = 0;
+ virtual RID _multimesh_get_buffer_rd_rid(RID p_multimesh) const = 0;
virtual Vector<float> _multimesh_get_buffer(RID p_multimesh) const = 0;
virtual void _multimesh_set_visible_instances(RID p_multimesh, int p_visible) = 0;
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index c0c6f1e904..2051d0caac 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -2452,6 +2452,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("multimesh_set_visible_instances", "multimesh", "visible"), &RenderingServer::multimesh_set_visible_instances);
ClassDB::bind_method(D_METHOD("multimesh_get_visible_instances", "multimesh"), &RenderingServer::multimesh_get_visible_instances);
ClassDB::bind_method(D_METHOD("multimesh_set_buffer", "multimesh", "buffer"), &RenderingServer::multimesh_set_buffer);
+ ClassDB::bind_method(D_METHOD("multimesh_get_buffer_rd_rid", "multimesh"), &RenderingServer::multimesh_get_buffer_rd_rid);
ClassDB::bind_method(D_METHOD("multimesh_get_buffer", "multimesh"), &RenderingServer::multimesh_get_buffer);
ClassDB::bind_method(D_METHOD("multimesh_set_buffer_interpolated", "multimesh", "buffer", "buffer_previous"), &RenderingServer::multimesh_set_buffer_interpolated);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 6de934aaeb..0917af73c6 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -475,6 +475,7 @@ public:
virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0;
virtual void multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) = 0;
+ virtual RID multimesh_get_buffer_rd_rid(RID p_multimesh) const = 0;
virtual Vector<float> multimesh_get_buffer(RID p_multimesh) const = 0;
// Interpolation.
diff --git a/tests/core/io/test_file_access.h b/tests/core/io/test_file_access.h
index a4d3fd1d70..00d33eaf30 100644
--- a/tests/core/io/test_file_access.h
+++ b/tests/core/io/test_file_access.h
@@ -39,7 +39,7 @@ namespace TestFileAccess {
TEST_CASE("[FileAccess] CSV read") {
Ref<FileAccess> f = FileAccess::open(TestUtils::get_data_path("testdata.csv"), FileAccess::READ);
- REQUIRE(!f.is_null());
+ REQUIRE(f.is_valid());
Vector<String> header = f->get_csv_line(); // Default delimiter: ",".
REQUIRE(header.size() == 4);
@@ -107,6 +107,98 @@ TEST_CASE("[FileAccess] Get as UTF-8 String") {
CHECK(s_cr == "Hello darkness\rMy old friend\rI've come to talk\rWith you again\r");
CHECK(s_cr_nocr == "Hello darknessMy old friendI've come to talkWith you again");
}
+
+TEST_CASE("[FileAccess] Get/Store floating point values") {
+ // BigEndian Hex: 0x40490E56
+ // LittleEndian Hex: 0x560E4940
+ float value = 3.1415f;
+
+ SUBCASE("Little Endian") {
+ const String file_path = TestUtils::get_data_path("floating_point_little_endian.bin");
+ const String file_path_new = TestUtils::get_data_path("floating_point_little_endian_new.bin");
+
+ Ref<FileAccess> f = FileAccess::open(file_path, FileAccess::READ);
+ REQUIRE(f.is_valid());
+ CHECK_EQ(f->get_float(), value);
+
+ Ref<FileAccess> fw = FileAccess::open(file_path_new, FileAccess::WRITE);
+ REQUIRE(fw.is_valid());
+ fw->store_float(value);
+ fw->close();
+
+ CHECK_EQ(FileAccess::get_sha256(file_path_new), FileAccess::get_sha256(file_path));
+
+ DirAccess::remove_file_or_error(file_path_new);
+ }
+
+ SUBCASE("Big Endian") {
+ const String file_path = TestUtils::get_data_path("floating_point_big_endian.bin");
+ const String file_path_new = TestUtils::get_data_path("floating_point_big_endian_new.bin");
+
+ Ref<FileAccess> f = FileAccess::open(file_path, FileAccess::READ);
+ REQUIRE(f.is_valid());
+ f->set_big_endian(true);
+ CHECK_EQ(f->get_float(), value);
+
+ Ref<FileAccess> fw = FileAccess::open(file_path_new, FileAccess::WRITE);
+ REQUIRE(fw.is_valid());
+ fw->set_big_endian(true);
+ fw->store_float(value);
+ fw->close();
+
+ CHECK_EQ(FileAccess::get_sha256(file_path_new), FileAccess::get_sha256(file_path));
+
+ DirAccess::remove_file_or_error(file_path_new);
+ }
+}
+
+TEST_CASE("[FileAccess] Get/Store floating point half precision values") {
+ // IEEE 754 half-precision binary floating-point format:
+ // sign exponent (5 bits) fraction (10 bits)
+ // 0 01101 0101010101
+ // BigEndian Hex: 0x3555
+ // LittleEndian Hex: 0x5535
+ float value = 0.33325195f;
+
+ SUBCASE("Little Endian") {
+ const String file_path = TestUtils::get_data_path("half_precision_floating_point_little_endian.bin");
+ const String file_path_new = TestUtils::get_data_path("half_precision_floating_point_little_endian_new.bin");
+
+ Ref<FileAccess> f = FileAccess::open(file_path, FileAccess::READ);
+ REQUIRE(f.is_valid());
+ CHECK_EQ(f->get_half(), value);
+
+ Ref<FileAccess> fw = FileAccess::open(file_path_new, FileAccess::WRITE);
+ REQUIRE(fw.is_valid());
+ fw->store_half(value);
+ fw->close();
+
+ CHECK_EQ(FileAccess::get_sha256(file_path_new), FileAccess::get_sha256(file_path));
+
+ DirAccess::remove_file_or_error(file_path_new);
+ }
+
+ SUBCASE("Big Endian") {
+ const String file_path = TestUtils::get_data_path("half_precision_floating_point_big_endian.bin");
+ const String file_path_new = TestUtils::get_data_path("half_precision_floating_point_big_endian_new.bin");
+
+ Ref<FileAccess> f = FileAccess::open(file_path, FileAccess::READ);
+ REQUIRE(f.is_valid());
+ f->set_big_endian(true);
+ CHECK_EQ(f->get_half(), value);
+
+ Ref<FileAccess> fw = FileAccess::open(file_path_new, FileAccess::WRITE);
+ REQUIRE(fw.is_valid());
+ fw->set_big_endian(true);
+ fw->store_half(value);
+ fw->close();
+
+ CHECK_EQ(FileAccess::get_sha256(file_path_new), FileAccess::get_sha256(file_path));
+
+ DirAccess::remove_file_or_error(file_path_new);
+ }
+}
+
} // namespace TestFileAccess
#endif // TEST_FILE_ACCESS_H
diff --git a/tests/core/io/test_marshalls.h b/tests/core/io/test_marshalls.h
index de8d6e1406..eb92c3f752 100644
--- a/tests/core/io/test_marshalls.h
+++ b/tests/core/io/test_marshalls.h
@@ -90,6 +90,20 @@ TEST_CASE("[Marshalls] Unsigned 64 bit integer decoding") {
CHECK(decode_uint64(arr) == 0x0f123456789abcdef);
}
+TEST_CASE("[Marshalls] Floating point half precision encoding") {
+ uint8_t arr[2];
+
+ // Decimal: 0.33325195
+ // IEEE 754 half-precision binary floating-point format:
+ // sign exponent (5 bits) fraction (10 bits)
+ // 0 01101 0101010101
+ // Hexadecimal: 0x3555
+ unsigned int actual_size = encode_half(0.33325195f, arr);
+ CHECK(actual_size == sizeof(uint16_t));
+ CHECK(arr[0] == 0x55);
+ CHECK(arr[1] == 0x35);
+}
+
TEST_CASE("[Marshalls] Floating point single precision encoding") {
uint8_t arr[4];
@@ -126,6 +140,13 @@ TEST_CASE("[Marshalls] Floating point double precision encoding") {
CHECK(arr[7] == 0x3f);
}
+TEST_CASE("[Marshalls] Floating point half precision decoding") {
+ uint8_t arr[] = { 0x55, 0x35 };
+
+ // See floating point half precision encoding test case for details behind expected values.
+ CHECK(decode_half(arr) == 0.33325195f);
+}
+
TEST_CASE("[Marshalls] Floating point single precision decoding") {
uint8_t arr[] = { 0x00, 0x00, 0x20, 0x3e };
@@ -160,7 +181,7 @@ TEST_CASE("[Marshalls] NIL Variant encoding") {
uint8_t buffer[4];
CHECK(encode_variant(variant, buffer, r_len) == OK);
- CHECK_MESSAGE(r_len == 4, "Length == 4 bytes for header");
+ CHECK_MESSAGE(r_len == 4, "Length == 4 bytes for header.");
CHECK_MESSAGE(buffer[0] == 0x00, "Variant::NIL");
CHECK(buffer[1] == 0x00);
CHECK(buffer[2] == 0x00);
@@ -174,7 +195,7 @@ TEST_CASE("[Marshalls] INT 32 bit Variant encoding") {
uint8_t buffer[8];
CHECK(encode_variant(variant, buffer, r_len) == OK);
- CHECK_MESSAGE(r_len == 8, "Length == 4 bytes for header + 4 bytes for int32_t");
+ CHECK_MESSAGE(r_len == 8, "Length == 4 bytes for header + 4 bytes for `int32_t`.");
CHECK_MESSAGE(buffer[0] == 0x02, "Variant::INT");
CHECK(buffer[1] == 0x00);
CHECK(buffer[2] == 0x00);
@@ -192,7 +213,7 @@ TEST_CASE("[Marshalls] INT 64 bit Variant encoding") {
uint8_t buffer[12];
CHECK(encode_variant(variant, buffer, r_len) == OK);
- CHECK_MESSAGE(r_len == 12, "Length == 4 bytes for header + 8 bytes for int64_t");
+ CHECK_MESSAGE(r_len == 12, "Length == 4 bytes for header + 8 bytes for `int64_t`.");
CHECK_MESSAGE(buffer[0] == 0x02, "Variant::INT");
CHECK(buffer[1] == 0x00);
CHECK_MESSAGE(buffer[2] == 0x01, "HEADER_DATA_FLAG_64");
@@ -214,7 +235,7 @@ TEST_CASE("[Marshalls] FLOAT single precision Variant encoding") {
uint8_t buffer[8];
CHECK(encode_variant(variant, buffer, r_len) == OK);
- CHECK_MESSAGE(r_len == 8, "Length == 4 bytes for header + 4 bytes for float");
+ CHECK_MESSAGE(r_len == 8, "Length == 4 bytes for header + 4 bytes for `float`.");
CHECK_MESSAGE(buffer[0] == 0x03, "Variant::FLOAT");
CHECK(buffer[1] == 0x00);
CHECK(buffer[2] == 0x00);
@@ -232,7 +253,7 @@ TEST_CASE("[Marshalls] FLOAT double precision Variant encoding") {
uint8_t buffer[12];
CHECK(encode_variant(variant, buffer, r_len) == OK);
- CHECK_MESSAGE(r_len == 12, "Length == 4 bytes for header + 8 bytes for double");
+ CHECK_MESSAGE(r_len == 12, "Length == 4 bytes for header + 8 bytes for `double`.");
CHECK_MESSAGE(buffer[0] == 0x03, "Variant::FLOAT");
CHECK(buffer[1] == 0x00);
CHECK_MESSAGE(buffer[2] == 0x01, "HEADER_DATA_FLAG_64");
@@ -335,10 +356,10 @@ TEST_CASE("[Marshalls] Typed array encoding") {
uint8_t buffer[24];
CHECK(encode_variant(array, buffer, r_len) == OK);
- CHECK_MESSAGE(r_len == 24, "Length == 4 bytes for header + 4 bytes for array type + 4 bytes for array size + 12 bytes for element");
+ CHECK_MESSAGE(r_len == 24, "Length == 4 bytes for header + 4 bytes for array type + 4 bytes for array size + 12 bytes for element.");
CHECK_MESSAGE(buffer[0] == 0x1c, "Variant::ARRAY");
CHECK(buffer[1] == 0x00);
- CHECK_MESSAGE(buffer[2] == 0x01, "HEADER_DATA_FIELD_TYPED_ARRAY_BUILTIN");
+ CHECK_MESSAGE(buffer[2] == 0x01, "CONTAINER_TYPE_KIND_BUILTIN");
CHECK(buffer[3] == 0x00);
// Check array type.
CHECK_MESSAGE(buffer[4] == 0x02, "Variant::INT");
@@ -370,7 +391,7 @@ TEST_CASE("[Marshalls] Typed array decoding") {
Variant variant;
int r_len;
uint8_t buffer[] = {
- 0x1c, 0x00, 0x01, 0x00, // Variant::ARRAY, HEADER_DATA_FIELD_TYPED_ARRAY_BUILTIN
+ 0x1c, 0x00, 0x01, 0x00, // Variant::ARRAY, CONTAINER_TYPE_KIND_BUILTIN
0x02, 0x00, 0x00, 0x00, // Array type (Variant::INT).
0x01, 0x00, 0x00, 0x00, // Array size.
0x02, 0x00, 0x01, 0x00, // Element type (Variant::INT, HEADER_DATA_FLAG_64).
@@ -386,6 +407,89 @@ TEST_CASE("[Marshalls] Typed array decoding") {
CHECK(array[0] == Variant(uint64_t(0x0f123456789abcdef)));
}
+TEST_CASE("[Marshalls] Typed dicttionary encoding") {
+ int r_len;
+ Dictionary dictionary;
+ dictionary.set_typed(Variant::INT, StringName(), Ref<Script>(), Variant::INT, StringName(), Ref<Script>());
+ dictionary[Variant(uint64_t(0x0f123456789abcdef))] = Variant(uint64_t(0x0f123456789abcdef));
+ uint8_t buffer[40];
+
+ CHECK(encode_variant(dictionary, buffer, r_len) == OK);
+ CHECK_MESSAGE(r_len == 40, "Length == 4 bytes for header + 8 bytes for dictionary type + 4 bytes for dictionary size + 24 bytes for key-value pair.");
+ CHECK_MESSAGE(buffer[0] == 0x1b, "Variant::DICTIONARY");
+ CHECK(buffer[1] == 0x00);
+ CHECK_MESSAGE(buffer[2] == 0x05, "key: CONTAINER_TYPE_KIND_BUILTIN | value: CONTAINER_TYPE_KIND_BUILTIN");
+ CHECK(buffer[3] == 0x00);
+ // Check dictionary key type.
+ CHECK_MESSAGE(buffer[4] == 0x02, "Variant::INT");
+ CHECK(buffer[5] == 0x00);
+ CHECK(buffer[6] == 0x00);
+ CHECK(buffer[7] == 0x00);
+ // Check dictionary value type.
+ CHECK_MESSAGE(buffer[8] == 0x02, "Variant::INT");
+ CHECK(buffer[9] == 0x00);
+ CHECK(buffer[10] == 0x00);
+ CHECK(buffer[11] == 0x00);
+ // Check dictionary size.
+ CHECK(buffer[12] == 0x01);
+ CHECK(buffer[13] == 0x00);
+ CHECK(buffer[14] == 0x00);
+ CHECK(buffer[15] == 0x00);
+ // Check key type.
+ CHECK_MESSAGE(buffer[16] == 0x02, "Variant::INT");
+ CHECK(buffer[17] == 0x00);
+ CHECK_MESSAGE(buffer[18] == 0x01, "HEADER_DATA_FLAG_64");
+ CHECK(buffer[19] == 0x00);
+ // Check key value.
+ CHECK(buffer[20] == 0xef);
+ CHECK(buffer[21] == 0xcd);
+ CHECK(buffer[22] == 0xab);
+ CHECK(buffer[23] == 0x89);
+ CHECK(buffer[24] == 0x67);
+ CHECK(buffer[25] == 0x45);
+ CHECK(buffer[26] == 0x23);
+ CHECK(buffer[27] == 0xf1);
+ // Check value type.
+ CHECK_MESSAGE(buffer[28] == 0x02, "Variant::INT");
+ CHECK(buffer[29] == 0x00);
+ CHECK_MESSAGE(buffer[30] == 0x01, "HEADER_DATA_FLAG_64");
+ CHECK(buffer[31] == 0x00);
+ // Check value value.
+ CHECK(buffer[32] == 0xef);
+ CHECK(buffer[33] == 0xcd);
+ CHECK(buffer[34] == 0xab);
+ CHECK(buffer[35] == 0x89);
+ CHECK(buffer[36] == 0x67);
+ CHECK(buffer[37] == 0x45);
+ CHECK(buffer[38] == 0x23);
+ CHECK(buffer[39] == 0xf1);
+}
+
+TEST_CASE("[Marshalls] Typed dictionary decoding") {
+ Variant variant;
+ int r_len;
+ uint8_t buffer[] = {
+ 0x1b, 0x00, 0x05, 0x00, // Variant::DICTIONARY, key: CONTAINER_TYPE_KIND_BUILTIN | value: CONTAINER_TYPE_KIND_BUILTIN
+ 0x02, 0x00, 0x00, 0x00, // Dictionary key type (Variant::INT).
+ 0x02, 0x00, 0x00, 0x00, // Dictionary value type (Variant::INT).
+ 0x01, 0x00, 0x00, 0x00, // Dictionary size.
+ 0x02, 0x00, 0x01, 0x00, // Key type (Variant::INT, HEADER_DATA_FLAG_64).
+ 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0xf1, // Key value.
+ 0x02, 0x00, 0x01, 0x00, // Value type (Variant::INT, HEADER_DATA_FLAG_64).
+ 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0xf1, // Value value.
+ };
+
+ CHECK(decode_variant(variant, buffer, 40, &r_len) == OK);
+ CHECK(r_len == 40);
+ CHECK(variant.get_type() == Variant::DICTIONARY);
+ Dictionary dictionary = variant;
+ CHECK(dictionary.get_typed_key_builtin() == Variant::INT);
+ CHECK(dictionary.get_typed_value_builtin() == Variant::INT);
+ CHECK(dictionary.size() == 1);
+ CHECK(dictionary.has(Variant(uint64_t(0x0f123456789abcdef))));
+ CHECK(dictionary[Variant(uint64_t(0x0f123456789abcdef))] == Variant(uint64_t(0x0f123456789abcdef)));
+}
+
} // namespace TestMarshalls
#endif // TEST_MARSHALLS_H
diff --git a/tests/core/io/test_stream_peer.h b/tests/core/io/test_stream_peer.h
index 31bd69edd0..961b4ac070 100644
--- a/tests/core/io/test_stream_peer.h
+++ b/tests/core/io/test_stream_peer.h
@@ -127,6 +127,17 @@ TEST_CASE("[StreamPeer] Get and sets through StreamPeerBuffer") {
CHECK_EQ(spb->get_u64(), value);
}
+ SUBCASE("A half-precision float value") {
+ float value = 3.1415927f;
+ float expected = 3.14062f;
+
+ spb->clear();
+ spb->put_half(value);
+ spb->seek(0);
+
+ CHECK(spb->get_half() == doctest::Approx(expected));
+ }
+
SUBCASE("A float value") {
float value = 42.0f;
@@ -255,6 +266,17 @@ TEST_CASE("[StreamPeer] Get and sets big endian through StreamPeerBuffer") {
CHECK_EQ(spb->get_float(), value);
}
+ SUBCASE("A half-precision float value") {
+ float value = 3.1415927f;
+ float expected = 3.14062f;
+
+ spb->clear();
+ spb->put_half(value);
+ spb->seek(0);
+
+ CHECK(spb->get_half() == doctest::Approx(expected));
+ }
+
SUBCASE("A double value") {
double value = 42.0;
diff --git a/modules/text_server_fb/thorvg_bounds_iterator.cpp b/tests/core/math/test_projection.h
index d273eef97f..7f41aaee3e 100644
--- a/modules/text_server_fb/thorvg_bounds_iterator.cpp
+++ b/tests/core/math/test_projection.h
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* thorvg_bounds_iterator.cpp */
+/* test_projection.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,43 +28,60 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifdef GDEXTENSION
-// Headers for building as GDExtension plug-in.
+#ifndef TEST_PROJECTION_H
+#define TEST_PROJECTION_H
-#include <godot_cpp/godot.hpp>
+#include "core/math/projection.h"
-using namespace godot;
+#include "core/string/print_string.h"
+#include "tests/test_macros.h"
-#elif defined(GODOT_MODULE)
-// Headers for building as built-in module.
+namespace TestProjection {
-#include "core/typedefs.h"
+TEST_CASE("[Projection] Default construct") {
+ Projection p;
+ CHECK(p.columns[0][0] == 1.0);
+ CHECK(p.columns[0][1] == 0.0);
+ CHECK(p.columns[0][2] == 0.0);
+ CHECK(p.columns[0][3] == 0.0);
-#include "modules/modules_enabled.gen.h" // For svg.
-#endif
+ CHECK(p.columns[1][0] == 0.0);
+ CHECK(p.columns[1][1] == 1.0);
+ CHECK(p.columns[1][2] == 0.0);
+ CHECK(p.columns[1][3] == 0.0);
-#ifdef MODULE_SVG_ENABLED
+ CHECK(p.columns[2][0] == 0.0);
+ CHECK(p.columns[2][1] == 0.0);
+ CHECK(p.columns[2][2] == 1.0);
+ CHECK(p.columns[2][3] == 0.0);
-#include "thorvg_bounds_iterator.h"
-
-#include <tvgIteratorAccessor.h>
-#include <tvgPaint.h>
-
-// This function uses private ThorVG API to get bounding box of top level children elements.
+ CHECK(p.columns[3][0] == 0.0);
+ CHECK(p.columns[3][1] == 0.0);
+ CHECK(p.columns[3][2] == 0.0);
+ CHECK(p.columns[3][3] == 1.0);
+}
-void tvg_get_bounds(tvg::Picture *p_picture, float &r_min_x, float &r_min_y, float &r_max_x, float &r_max_y) {
- tvg::IteratorAccessor itrAccessor;
- if (tvg::Iterator *it = itrAccessor.iterator(p_picture)) {
- while (const tvg::Paint *child = it->next()) {
- float x = 0, y = 0, w = 0, h = 0;
- child->bounds(&x, &y, &w, &h, true);
- r_min_x = MIN(x, r_min_x);
- r_min_y = MIN(y, r_min_y);
- r_max_x = MAX(x + w, r_max_x);
- r_max_y = MAX(y + h, r_max_y);
+bool projection_is_equal_approx(const Projection &p_a, const Projection &p_b) {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ if (!Math::is_equal_approx(p_a.columns[i][j], p_b.columns[i][j])) {
+ return false;
+ }
}
- delete (it);
}
+ return true;
+}
+
+TEST_CASE("[Projection] Orthogonal projection matrix inversion") {
+ Projection p = Projection::create_orthogonal(-125.0f, 125.0f, -125.0f, 125.0f, 0.01f, 25.0f);
+ CHECK(projection_is_equal_approx(p.inverse() * p, Projection()));
+}
+
+TEST_CASE("[Projection] Perspective projection matrix inversion") {
+ Projection p = Projection::create_perspective(90.0f, 1.77777f, 0.05f, 4000.0f);
+ CHECK(projection_is_equal_approx(p.inverse() * p, Projection()));
}
-#endif // MODULE_SVG_ENABLED
+} //namespace TestProjection
+
+#endif // TEST_PROJECTION_H
diff --git a/tests/core/object/test_class_db.h b/tests/core/object/test_class_db.h
index 924e93129d..b38d3d3e61 100644
--- a/tests/core/object/test_class_db.h
+++ b/tests/core/object/test_class_db.h
@@ -863,16 +863,19 @@ void add_global_enums(Context &r_context) {
}
}
- // HARDCODED
- List<StringName> hardcoded_enums;
- hardcoded_enums.push_back("Vector2.Axis");
- hardcoded_enums.push_back("Vector2i.Axis");
- hardcoded_enums.push_back("Vector3.Axis");
- hardcoded_enums.push_back("Vector3i.Axis");
- for (const StringName &E : hardcoded_enums) {
- // These enums are not generated and must be written manually (e.g.: Vector3.Axis)
- // Here, we assume core types do not begin with underscore
- r_context.enum_types.push_back(E);
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ if (i == Variant::OBJECT) {
+ continue;
+ }
+
+ const Variant::Type type = Variant::Type(i);
+
+ List<StringName> enum_names;
+ Variant::get_enums_for_type(type, &enum_names);
+
+ for (const StringName &enum_name : enum_names) {
+ r_context.enum_types.push_back(Variant::get_type_name(type) + "." + enum_name);
+ }
}
}
diff --git a/tests/core/string/test_translation_server.h b/tests/core/string/test_translation_server.h
index 4edc36d29f..1274d8810e 100644
--- a/tests/core/string/test_translation_server.h
+++ b/tests/core/string/test_translation_server.h
@@ -104,6 +104,36 @@ TEST_CASE("[TranslationServer] Locale operations") {
res = ts->standardize_locale(loc);
CHECK(res == "de_DE");
+
+ // No added defaults.
+ loc = "es_ES";
+ res = ts->standardize_locale(loc, true);
+
+ CHECK(res == "es_ES");
+
+ // Add default script.
+ loc = "az_AZ";
+ res = ts->standardize_locale(loc, true);
+
+ CHECK(res == "az_Latn_AZ");
+
+ // Add default country.
+ loc = "pa_Arab";
+ res = ts->standardize_locale(loc, true);
+
+ CHECK(res == "pa_Arab_PK");
+
+ // Add default script and country.
+ loc = "zh";
+ res = ts->standardize_locale(loc, true);
+
+ CHECK(res == "zh_Hans_CN");
+
+ // Explicitly don't add defaults.
+ loc = "zh";
+ res = ts->standardize_locale(loc, false);
+
+ CHECK(res == "zh");
}
TEST_CASE("[TranslationServer] Comparing locales") {
@@ -120,18 +150,50 @@ TEST_CASE("[TranslationServer] Comparing locales") {
locale_a = "sr-Latn-CS";
locale_b = "sr-Latn-RS";
- // Two elements from locales match.
+ // Script matches (+1) but country doesn't (-1).
res = ts->compare_locales(locale_a, locale_b);
- CHECK(res == 2);
+ CHECK(res == 5);
locale_a = "uz-Cyrl-UZ";
locale_b = "uz-Latn-UZ";
- // Two elements match, but they are not sequentual.
+ // Country matches (+1) but script doesn't (-1).
+ res = ts->compare_locales(locale_a, locale_b);
+
+ CHECK(res == 5);
+
+ locale_a = "aa-Latn-ER";
+ locale_b = "aa-Latn-ER-saaho";
+
+ // Script and country match (+2) with variant on one locale (+0).
+ res = ts->compare_locales(locale_a, locale_b);
+
+ CHECK(res == 7);
+
+ locale_a = "uz-Cyrl-UZ";
+ locale_b = "uz-Latn-KG";
+
+ // Both script and country mismatched (-2).
+ res = ts->compare_locales(locale_a, locale_b);
+
+ CHECK(res == 3);
+
+ locale_a = "es-ES";
+ locale_b = "es-AR";
+
+ // Mismatched country (-1).
+ res = ts->compare_locales(locale_a, locale_b);
+
+ CHECK(res == 4);
+
+ locale_a = "es";
+ locale_b = "es-AR";
+
+ // No country for one locale (+0).
res = ts->compare_locales(locale_a, locale_b);
- CHECK(res == 2);
+ CHECK(res == 5);
locale_a = "es-EC";
locale_b = "fr-LU";
@@ -140,6 +202,24 @@ TEST_CASE("[TranslationServer] Comparing locales") {
res = ts->compare_locales(locale_a, locale_b);
CHECK(res == 0);
+
+ locale_a = "zh-HK";
+ locale_b = "zh";
+
+ // In full standardization, zh-HK becomes zh_Hant_HK and zh becomes
+ // zh_Hans_CN. Both script and country mismatch (-2).
+ res = ts->compare_locales(locale_a, locale_b);
+
+ CHECK(res == 3);
+
+ locale_a = "zh-CN";
+ locale_b = "zh";
+
+ // In full standardization, zh and zh-CN both become zh_Hans_CN for an
+ // exact match.
+ res = ts->compare_locales(locale_a, locale_b);
+
+ CHECK(res == 10);
}
} // namespace TestTranslationServer
diff --git a/tests/core/variant/test_callable.h b/tests/core/variant/test_callable.h
index 3228e0a583..34ea8fad5c 100644
--- a/tests/core/variant/test_callable.h
+++ b/tests/core/variant/test_callable.h
@@ -135,6 +135,70 @@ TEST_CASE("[Callable] Argument count") {
memdelete(my_test);
}
+
+class TestBoundUnboundArgumentCount : public Object {
+ GDCLASS(TestBoundUnboundArgumentCount, Object);
+
+protected:
+ static void _bind_methods() {
+ ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "test_func", &TestBoundUnboundArgumentCount::test_func, MethodInfo("test_func"));
+ }
+
+public:
+ Variant test_func(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ Array result;
+ result.resize(p_argcount);
+ for (int i = 0; i < p_argcount; i++) {
+ result[i] = *p_args[i];
+ }
+ return result;
+ }
+
+ static String get_output(const Callable &p_callable) {
+ Array effective_args;
+ effective_args.push_back(7);
+ effective_args.push_back(8);
+ effective_args.push_back(9);
+
+ effective_args.resize(3 - p_callable.get_unbound_arguments_count());
+ effective_args.append_array(p_callable.get_bound_arguments());
+
+ return vformat(
+ "%d %d %s %s %s",
+ p_callable.get_unbound_arguments_count(),
+ p_callable.get_bound_arguments_count(),
+ p_callable.get_bound_arguments(),
+ p_callable.call(7, 8, 9),
+ effective_args);
+ }
+};
+
+TEST_CASE("[Callable] Bound and unbound argument count") {
+ String (*get_output)(const Callable &) = TestBoundUnboundArgumentCount::get_output;
+
+ TestBoundUnboundArgumentCount *test_instance = memnew(TestBoundUnboundArgumentCount);
+
+ Callable test_func = Callable(test_instance, "test_func");
+
+ CHECK(get_output(test_func) == "0 0 [] [7, 8, 9] [7, 8, 9]");
+ CHECK(get_output(test_func.bind(1, 2)) == "0 2 [1, 2] [7, 8, 9, 1, 2] [7, 8, 9, 1, 2]");
+ CHECK(get_output(test_func.bind(1, 2).unbind(1)) == "1 2 [1, 2] [7, 8, 1, 2] [7, 8, 1, 2]");
+ CHECK(get_output(test_func.bind(1, 2).unbind(1).bind(3, 4)) == "0 3 [3, 1, 2] [7, 8, 9, 3, 1, 2] [7, 8, 9, 3, 1, 2]");
+ CHECK(get_output(test_func.bind(1, 2).unbind(1).bind(3, 4).unbind(1)) == "1 3 [3, 1, 2] [7, 8, 3, 1, 2] [7, 8, 3, 1, 2]");
+
+ CHECK(get_output(test_func.bind(1).bind(2).bind(3).unbind(1)) == "1 3 [3, 2, 1] [7, 8, 3, 2, 1] [7, 8, 3, 2, 1]");
+ CHECK(get_output(test_func.bind(1).bind(2).unbind(1).bind(3)) == "0 2 [2, 1] [7, 8, 9, 2, 1] [7, 8, 9, 2, 1]");
+ CHECK(get_output(test_func.bind(1).unbind(1).bind(2).bind(3)) == "0 2 [3, 1] [7, 8, 9, 3, 1] [7, 8, 9, 3, 1]");
+ CHECK(get_output(test_func.unbind(1).bind(1).bind(2).bind(3)) == "0 2 [3, 2] [7, 8, 9, 3, 2] [7, 8, 9, 3, 2]");
+
+ CHECK(get_output(test_func.unbind(1).unbind(1).unbind(1).bind(1, 2, 3)) == "0 0 [] [7, 8, 9] [7, 8, 9]");
+ CHECK(get_output(test_func.unbind(1).unbind(1).bind(1, 2, 3).unbind(1)) == "1 1 [1] [7, 8, 1] [7, 8, 1]");
+ CHECK(get_output(test_func.unbind(1).bind(1, 2, 3).unbind(1).unbind(1)) == "2 2 [1, 2] [7, 1, 2] [7, 1, 2]");
+ CHECK(get_output(test_func.bind(1, 2, 3).unbind(1).unbind(1).unbind(1)) == "3 3 [1, 2, 3] [1, 2, 3] [1, 2, 3]");
+
+ memdelete(test_instance);
+}
+
} // namespace TestCallable
#endif // TEST_CALLABLE_H
diff --git a/tests/data/floating_point_big_endian.bin b/tests/data/floating_point_big_endian.bin
new file mode 100644
index 0000000000..9534605ce1
--- /dev/null
+++ b/tests/data/floating_point_big_endian.bin
@@ -0,0 +1 @@
+@IV \ No newline at end of file
diff --git a/tests/data/floating_point_little_endian.bin b/tests/data/floating_point_little_endian.bin
new file mode 100644
index 0000000000..8cd66219d8
--- /dev/null
+++ b/tests/data/floating_point_little_endian.bin
@@ -0,0 +1 @@
+VI@ \ No newline at end of file
diff --git a/tests/data/half_precision_floating_point_big_endian.bin b/tests/data/half_precision_floating_point_big_endian.bin
new file mode 100644
index 0000000000..6519f7500a
--- /dev/null
+++ b/tests/data/half_precision_floating_point_big_endian.bin
@@ -0,0 +1 @@
+5U \ No newline at end of file
diff --git a/tests/data/half_precision_floating_point_little_endian.bin b/tests/data/half_precision_floating_point_little_endian.bin
new file mode 100644
index 0000000000..4f748ab1e9
--- /dev/null
+++ b/tests/data/half_precision_floating_point_little_endian.bin
@@ -0,0 +1 @@
+U5 \ No newline at end of file
diff --git a/tests/scene/test_fontfile.h b/tests/scene/test_fontfile.h
new file mode 100644
index 0000000000..8c9ba6d6ff
--- /dev/null
+++ b/tests/scene/test_fontfile.h
@@ -0,0 +1,82 @@
+/**************************************************************************/
+/* test_fontfile.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef TEST_FONTFILE_H
+#define TEST_FONTFILE_H
+
+#include "modules/modules_enabled.gen.h"
+
+#include "scene/resources/font.h"
+#include "tests/test_macros.h"
+
+namespace TestFontfile {
+
+TEST_CASE("[FontFile] Create font file and check data") {
+ // Create test instance.
+ Ref<FontFile> font_file;
+ font_file.instantiate();
+
+#ifdef MODULE_FREETYPE_ENABLED
+ // Try to load non-existent files.
+ ERR_PRINT_OFF
+ CHECK(font_file->load_dynamic_font("") == OK);
+ CHECK_MESSAGE(font_file->get_data().is_empty() == true, "Invalid fontfile should not be loaded.");
+
+ CHECK(font_file->load_dynamic_font("thirdparty/fonts/nofonthasthisname.woff2") == OK);
+ CHECK_MESSAGE(font_file->get_data().is_empty() == true, "Invalid fontfile should not be loaded.");
+ ERR_PRINT_ON
+
+ // Load a valid file.
+ CHECK(font_file->load_dynamic_font("thirdparty/fonts/NotoSans_Regular.woff2") == OK);
+
+ // Check fontfile data.
+ CHECK_MESSAGE(font_file->get_data().is_empty() == false, "Fontfile should have been loaded.");
+ CHECK_MESSAGE(font_file->get_font_name() == "Noto Sans", "Loaded correct font name.");
+ CHECK_MESSAGE(font_file->get_font_style_name() == "Regular", "Loaded correct font style.");
+ CHECK_MESSAGE(font_file->get_data().size() == 148480llu, "Whole fontfile was loaded.");
+
+ // Valid glyphs.
+ CHECK_MESSAGE(font_file->get_glyph_index(2, 'a', 0) != 0, "Glyph index for 'a' is valid.");
+ CHECK_MESSAGE(font_file->get_glyph_index(2, 'b', 0) != 0, "Glyph index for 'b' is valid.");
+ CHECK_MESSAGE(font_file->get_glyph_index(2, 0x0103, 0) != 0, "Glyph index for 'latin small letter a with breve' is valid.");
+ CHECK_MESSAGE(font_file->get_glyph_index(2, 0x03a8, 0) != 0, "Glyph index for 'Greek psi' is valid.");
+ CHECK_MESSAGE(font_file->get_glyph_index(2, 0x0416, 0) != 0, "Glyph index for 'Cyrillic zhe' is valid.");
+ CHECK_MESSAGE(font_file->get_glyph_index(2, '&', 0) != 0, "Glyph index for '&' is valid.");
+
+ // Invalid glyphs.
+ CHECK_MESSAGE(font_file->get_glyph_index(2, 0x4416, 0) == 0, "Glyph index is invalid.");
+ CHECK_MESSAGE(font_file->get_glyph_index(2, 0x5555, 0) == 0, "Glyph index is invalid.");
+ CHECK_MESSAGE(font_file->get_glyph_index(2, 0x2901, 0) == 0, "Glyph index is invalid.");
+#endif
+}
+
+} // namespace TestFontfile
+
+#endif // TEST_FONTFILE_H
diff --git a/tests/scene/test_texture_progress_bar.h b/tests/scene/test_texture_progress_bar.h
new file mode 100644
index 0000000000..5eb7495a29
--- /dev/null
+++ b/tests/scene/test_texture_progress_bar.h
@@ -0,0 +1,92 @@
+/**************************************************************************/
+/* test_texture_progress_bar.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef TEST_TEXTURE_PROGRESS_BAR_H
+#define TEST_TEXTURE_PROGRESS_BAR_H
+
+#include "scene/gui/texture_progress_bar.h"
+
+#include "tests/test_macros.h"
+
+namespace TestTextureProgressBar {
+
+TEST_CASE("[SceneTree][TextureProgressBar]") {
+ TextureProgressBar *texture_progress_bar = memnew(TextureProgressBar);
+
+ SUBCASE("[TextureProgressBar] set_radial_initial_angle() should wrap angle between 0 and 360 degrees (inclusive).") {
+ texture_progress_bar->set_radial_initial_angle(0.0);
+ CHECK(Math::is_equal_approx(texture_progress_bar->get_radial_initial_angle(), (float)0.0));
+
+ texture_progress_bar->set_radial_initial_angle(360.0);
+ CHECK(Math::is_equal_approx(texture_progress_bar->get_radial_initial_angle(), (float)360.0));
+
+ texture_progress_bar->set_radial_initial_angle(30.5);
+ CHECK(Math::is_equal_approx(texture_progress_bar->get_radial_initial_angle(), (float)30.5));
+
+ texture_progress_bar->set_radial_initial_angle(-30.5);
+ CHECK(Math::is_equal_approx(texture_progress_bar->get_radial_initial_angle(), (float)(360 - 30.5)));
+
+ texture_progress_bar->set_radial_initial_angle(36000 + 30.5);
+ CHECK(Math::is_equal_approx(texture_progress_bar->get_radial_initial_angle(), (float)30.5));
+
+ texture_progress_bar->set_radial_initial_angle(-(36000 + 30.5));
+ CHECK(Math::is_equal_approx(texture_progress_bar->get_radial_initial_angle(), (float)(360 - 30.5)));
+ }
+
+ SUBCASE("[TextureProgressBar] set_radial_initial_angle() should not set non-finite values.") {
+ texture_progress_bar->set_radial_initial_angle(30.5);
+
+ ERR_PRINT_OFF;
+ texture_progress_bar->set_radial_initial_angle(INFINITY);
+ ERR_PRINT_ON;
+ CHECK(Math::is_equal_approx(texture_progress_bar->get_radial_initial_angle(), (float)30.5));
+
+ ERR_PRINT_OFF;
+ texture_progress_bar->set_radial_initial_angle(-INFINITY);
+ ERR_PRINT_ON;
+ CHECK(Math::is_equal_approx(texture_progress_bar->get_radial_initial_angle(), (float)30.5));
+
+ ERR_PRINT_OFF;
+ texture_progress_bar->set_radial_initial_angle(NAN);
+ ERR_PRINT_ON;
+ CHECK(Math::is_equal_approx(texture_progress_bar->get_radial_initial_angle(), (float)30.5));
+
+ ERR_PRINT_OFF;
+ texture_progress_bar->set_radial_initial_angle(-NAN);
+ ERR_PRINT_ON;
+ CHECK(Math::is_equal_approx(texture_progress_bar->get_radial_initial_angle(), (float)30.5));
+ }
+
+ memdelete(texture_progress_bar);
+}
+
+} // namespace TestTextureProgressBar
+
+#endif // TEST_TEXTURE_PROGRESS_BAR_H
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index 65d45ae92f..9acdc98b1d 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -65,6 +65,7 @@
#include "tests/core/math/test_geometry_3d.h"
#include "tests/core/math/test_math_funcs.h"
#include "tests/core/math/test_plane.h"
+#include "tests/core/math/test_projection.h"
#include "tests/core/math/test_quaternion.h"
#include "tests/core/math/test_random_number_generator.h"
#include "tests/core/math/test_rect2.h"
@@ -116,6 +117,7 @@
#include "tests/scene/test_curve.h"
#include "tests/scene/test_curve_2d.h"
#include "tests/scene/test_curve_3d.h"
+#include "tests/scene/test_fontfile.h"
#include "tests/scene/test_gradient.h"
#include "tests/scene/test_gradient_texture.h"
#include "tests/scene/test_image_texture.h"
@@ -130,6 +132,7 @@
#include "tests/scene/test_physics_material.h"
#include "tests/scene/test_sprite_frames.h"
#include "tests/scene/test_style_box_texture.h"
+#include "tests/scene/test_texture_progress_bar.h"
#include "tests/scene/test_theme.h"
#include "tests/scene/test_timer.h"
#include "tests/scene/test_viewport.h"
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 7a95e3c724..291ab1164d 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -111,7 +111,7 @@ Files extracted from upstream source:
## clipper2
- Upstream: https://github.com/AngusJohnson/Clipper2
-- Version: 1.3.0 (98db5662e8dd1808a5a7b50c5605a2289bb390e8, 2023)
+- Version: 1.4.0 (736ddb0b53d97fd5f65dd3d9bbf8a0993eaf387c, 2024)
- License: BSL 1.0
Files extracted from upstream source:
diff --git a/thirdparty/clipper2/include/clipper2/clipper.core.h b/thirdparty/clipper2/include/clipper2/clipper.core.h
index 0de7c3720e..0f69bf2d9f 100644
--- a/thirdparty/clipper2/include/clipper2/clipper.core.h
+++ b/thirdparty/clipper2/include/clipper2/clipper.core.h
@@ -1,8 +1,8 @@
/*******************************************************************************
* Author : Angus Johnson *
-* Date : 24 November 2023 *
+* Date : 12 May 2024 *
* Website : http://www.angusj.com *
-* Copyright : Angus Johnson 2010-2023 *
+* Copyright : Angus Johnson 2010-2024 *
* Purpose : Core Clipper Library structures and functions *
* License : http://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************/
@@ -19,6 +19,7 @@
#include <algorithm>
#include <climits>
#include <numeric>
+#include <optional>
#include "clipper2/clipper.version.h"
#define CLIPPER2_THROW(exception) std::abort()
@@ -51,19 +52,19 @@ namespace Clipper2Lib
// error codes (2^n)
const int precision_error_i = 1; // non-fatal
- const int scale_error_i = 2; // non-fatal
- const int non_pair_error_i = 4; // non-fatal
- const int undefined_error_i = 32; // fatal
+ const int scale_error_i = 2; // non-fatal
+ const int non_pair_error_i = 4; // non-fatal
+ const int undefined_error_i = 32; // fatal
const int range_error_i = 64;
#ifndef PI
static const double PI = 3.141592653589793238;
#endif
-#ifdef CLIPPER2_MAX_PRECISION
- const int MAX_DECIMAL_PRECISION = CLIPPER2_MAX_PRECISION;
+#ifdef CLIPPER2_MAX_DECIMAL_PRECISION
+ const int CLIPPER2_MAX_DEC_PRECISION = CLIPPER2_MAX_DECIMAL_PRECISION;
#else
- const int MAX_DECIMAL_PRECISION = 8; // see Discussions #564
+ const int CLIPPER2_MAX_DEC_PRECISION = 8; // see Discussions #564
#endif
static const int64_t MAX_COORD = INT64_MAX >> 2;
@@ -74,7 +75,7 @@ namespace Clipper2Lib
static const double MAX_DBL = (std::numeric_limits<double>::max)();
- static void DoError(int error_code)
+ static void DoError([[maybe_unused]] int error_code)
{
#if (defined(__cpp_exceptions) && __cpp_exceptions) || (defined(__EXCEPTIONS) && __EXCEPTIONS)
switch (error_code)
@@ -95,6 +96,13 @@ namespace Clipper2Lib
#endif
}
+ // can we call std::round on T? (default false) (#824)
+ template <typename T, typename = void>
+ struct is_round_invocable : std::false_type {};
+
+ template <typename T>
+ struct is_round_invocable<T, std::void_t<decltype(std::round(std::declval<T>()))>> : std::true_type {};
+
//By far the most widely used filling rules for polygons are EvenOdd
//and NonZero, sometimes called Alternate and Winding respectively.
@@ -113,8 +121,8 @@ namespace Clipper2Lib
template <typename T2>
inline void Init(const T2 x_ = 0, const T2 y_ = 0, const int64_t z_ = 0)
{
- if constexpr (std::numeric_limits<T>::is_integer &&
- !std::numeric_limits<T2>::is_integer)
+ if constexpr (std::is_integral_v<T> &&
+ is_round_invocable<T2>::value && !std::is_integral_v<T2>)
{
x = static_cast<T>(std::round(x_));
y = static_cast<T>(std::round(y_));
@@ -143,6 +151,12 @@ namespace Clipper2Lib
Init(p.x, p.y, p.z);
}
+ template <typename T2>
+ explicit Point(const Point<T2>& p, int64_t z_)
+ {
+ Init(p.x, p.y, z_);
+ }
+
Point operator * (const double scale) const
{
return Point(x * scale, y * scale, z);
@@ -161,8 +175,8 @@ namespace Clipper2Lib
template <typename T2>
inline void Init(const T2 x_ = 0, const T2 y_ = 0)
{
- if constexpr (std::numeric_limits<T>::is_integer &&
- !std::numeric_limits<T2>::is_integer)
+ if constexpr (std::is_integral_v<T> &&
+ is_round_invocable<T2>::value && !std::is_integral_v<T2>)
{
x = static_cast<T>(std::round(x_));
y = static_cast<T>(std::round(y_));
@@ -244,6 +258,14 @@ namespace Clipper2Lib
(std::numeric_limits<double>::max)(),
(std::numeric_limits<double>::max)());
+ template<typename T>
+ static inline Point<T> MidPoint(const Point<T>& p1, const Point<T>& p2)
+ {
+ Point<T> result;
+ result.x = (p1.x + p2.x) / 2;
+ result.y = (p1.y + p2.y) / 2;
+ return result;
+ }
// Rect ------------------------------------------------------------------------
@@ -275,10 +297,19 @@ namespace Clipper2Lib
else
{
left = top = (std::numeric_limits<T>::max)();
- right = bottom = (std::numeric_limits<T>::lowest)();
+ right = bottom = std::numeric_limits<T>::lowest();
}
}
+ static Rect<T> InvalidRect()
+ {
+ return {
+ (std::numeric_limits<T>::max)(),
+ (std::numeric_limits<T>::max)(),
+ std::numeric_limits<T>::lowest(),
+ std::numeric_limits<T>::lowest() };
+ }
+
bool IsValid() const { return left != (std::numeric_limits<T>::max)(); }
T Width() const { return right - left; }
@@ -329,7 +360,7 @@ namespace Clipper2Lib
};
bool operator==(const Rect<T>& other) const {
- return left == other.left && right == other.right &&
+ return left == other.left && right == other.right &&
top == other.top && bottom == other.bottom;
}
@@ -344,8 +375,8 @@ namespace Clipper2Lib
{
Rect<T1> result;
- if constexpr (std::numeric_limits<T1>::is_integer &&
- !std::numeric_limits<T2>::is_integer)
+ if constexpr (std::is_integral_v<T1> &&
+ is_round_invocable<T2>::value && !std::is_integral_v<T2>)
{
result.left = static_cast<T1>(std::round(rect.left * scale));
result.top = static_cast<T1>(std::round(rect.top * scale));
@@ -354,32 +385,24 @@ namespace Clipper2Lib
}
else
{
- result.left = rect.left * scale;
- result.top = rect.top * scale;
- result.right = rect.right * scale;
- result.bottom = rect.bottom * scale;
+ result.left = static_cast<T1>(rect.left * scale);
+ result.top = static_cast<T1>(rect.top * scale);
+ result.right = static_cast<T1>(rect.right * scale);
+ result.bottom = static_cast<T1>(rect.bottom * scale);
}
return result;
}
- static const Rect64 InvalidRect64 = Rect64(
- (std::numeric_limits<int64_t>::max)(),
- (std::numeric_limits<int64_t>::max)(),
- (std::numeric_limits<int64_t>::lowest)(),
- (std::numeric_limits<int64_t>::lowest)());
- static const RectD InvalidRectD = RectD(
- (std::numeric_limits<double>::max)(),
- (std::numeric_limits<double>::max)(),
- (std::numeric_limits<double>::lowest)(),
- (std::numeric_limits<double>::lowest)());
+ static const Rect64 InvalidRect64 = Rect64::InvalidRect();
+ static const RectD InvalidRectD = RectD::InvalidRect();
template <typename T>
Rect<T> GetBounds(const Path<T>& path)
{
- auto xmin = (std::numeric_limits<T>::max)();
- auto ymin = (std::numeric_limits<T>::max)();
- auto xmax = std::numeric_limits<T>::lowest();
- auto ymax = std::numeric_limits<T>::lowest();
+ T xmin = (std::numeric_limits<T>::max)();
+ T ymin = (std::numeric_limits<T>::max)();
+ T xmax = std::numeric_limits<T>::lowest();
+ T ymax = std::numeric_limits<T>::lowest();
for (const auto& p : path)
{
if (p.x < xmin) xmin = p.x;
@@ -393,17 +416,52 @@ namespace Clipper2Lib
template <typename T>
Rect<T> GetBounds(const Paths<T>& paths)
{
- auto xmin = (std::numeric_limits<T>::max)();
- auto ymin = (std::numeric_limits<T>::max)();
- auto xmax = std::numeric_limits<T>::lowest();
- auto ymax = std::numeric_limits<T>::lowest();
+ T xmin = (std::numeric_limits<T>::max)();
+ T ymin = (std::numeric_limits<T>::max)();
+ T xmax = std::numeric_limits<T>::lowest();
+ T ymax = std::numeric_limits<T>::lowest();
for (const Path<T>& path : paths)
for (const Point<T>& p : path)
{
- if (p.x < xmin) xmin = p.x;
- if (p.x > xmax) xmax = p.x;
- if (p.y < ymin) ymin = p.y;
- if (p.y > ymax) ymax = p.y;
+ if (p.x < xmin) xmin = p.x;
+ if (p.x > xmax) xmax = p.x;
+ if (p.y < ymin) ymin = p.y;
+ if (p.y > ymax) ymax = p.y;
+ }
+ return Rect<T>(xmin, ymin, xmax, ymax);
+ }
+
+ template <typename T, typename T2>
+ Rect<T> GetBounds(const Path<T2>& path)
+ {
+ T xmin = (std::numeric_limits<T>::max)();
+ T ymin = (std::numeric_limits<T>::max)();
+ T xmax = std::numeric_limits<T>::lowest();
+ T ymax = std::numeric_limits<T>::lowest();
+ for (const auto& p : path)
+ {
+ if (p.x < xmin) xmin = static_cast<T>(p.x);
+ if (p.x > xmax) xmax = static_cast<T>(p.x);
+ if (p.y < ymin) ymin = static_cast<T>(p.y);
+ if (p.y > ymax) ymax = static_cast<T>(p.y);
+ }
+ return Rect<T>(xmin, ymin, xmax, ymax);
+ }
+
+ template <typename T, typename T2>
+ Rect<T> GetBounds(const Paths<T2>& paths)
+ {
+ T xmin = (std::numeric_limits<T>::max)();
+ T ymin = (std::numeric_limits<T>::max)();
+ T xmax = std::numeric_limits<T>::lowest();
+ T ymax = std::numeric_limits<T>::lowest();
+ for (const Path<T2>& path : paths)
+ for (const Point<T2>& p : path)
+ {
+ if (p.x < xmin) xmin = static_cast<T>(p.x);
+ if (p.x > xmax) xmax = static_cast<T>(p.x);
+ if (p.y < ymin) ymin = static_cast<T>(p.y);
+ if (p.y > ymax) ymax = static_cast<T>(p.y);
}
return Rect<T>(xmin, ymin, xmax, ymax);
}
@@ -431,7 +489,7 @@ namespace Clipper2Lib
template <typename T1, typename T2>
- inline Path<T1> ScalePath(const Path<T2>& path,
+ inline Path<T1> ScalePath(const Path<T2>& path,
double scale_x, double scale_y, int& error_code)
{
Path<T1> result;
@@ -447,11 +505,11 @@ namespace Clipper2Lib
result.reserve(path.size());
#ifdef USINGZ
std::transform(path.begin(), path.end(), back_inserter(result),
- [scale_x, scale_y](const auto& pt)
+ [scale_x, scale_y](const auto& pt)
{ return Point<T1>(pt.x * scale_x, pt.y * scale_y, pt.z); });
#else
std::transform(path.begin(), path.end(), back_inserter(result),
- [scale_x, scale_y](const auto& pt)
+ [scale_x, scale_y](const auto& pt)
{ return Point<T1>(pt.x * scale_x, pt.y * scale_y); });
#endif
return result;
@@ -465,20 +523,19 @@ namespace Clipper2Lib
}
template <typename T1, typename T2>
- inline Paths<T1> ScalePaths(const Paths<T2>& paths,
+ inline Paths<T1> ScalePaths(const Paths<T2>& paths,
double scale_x, double scale_y, int& error_code)
{
Paths<T1> result;
- if constexpr (std::numeric_limits<T1>::is_integer &&
- !std::numeric_limits<T2>::is_integer)
+ if constexpr (std::is_integral_v<T1>)
{
- RectD r = GetBounds(paths);
+ RectD r = GetBounds<double, T2>(paths);
if ((r.left * scale_x) < min_coord ||
(r.right * scale_x) > max_coord ||
(r.top * scale_y) < min_coord ||
(r.bottom * scale_y) > max_coord)
- {
+ {
error_code |= range_error_i;
DoError(range_error_i);
return result; // empty path
@@ -493,7 +550,7 @@ namespace Clipper2Lib
}
template <typename T1, typename T2>
- inline Paths<T1> ScalePaths(const Paths<T2>& paths,
+ inline Paths<T1> ScalePaths(const Paths<T2>& paths,
double scale, int& error_code)
{
return ScalePaths<T1, T2>(paths, scale, scale, error_code);
@@ -590,20 +647,94 @@ namespace Clipper2Lib
// Miscellaneous ------------------------------------------------------------
- inline void CheckPrecision(int& precision, int& error_code)
+ inline void CheckPrecisionRange(int& precision, int& error_code)
{
- if (precision >= -MAX_DECIMAL_PRECISION && precision <= MAX_DECIMAL_PRECISION) return;
+ if (precision >= -CLIPPER2_MAX_DEC_PRECISION &&
+ precision <= CLIPPER2_MAX_DEC_PRECISION) return;
error_code |= precision_error_i; // non-fatal error
- DoError(precision_error_i); // does nothing unless exceptions enabled
- precision = precision > 0 ? MAX_DECIMAL_PRECISION : -MAX_DECIMAL_PRECISION;
+ DoError(precision_error_i); // does nothing when exceptions are disabled
+ precision = precision > 0 ? CLIPPER2_MAX_DEC_PRECISION : -CLIPPER2_MAX_DEC_PRECISION;
}
- inline void CheckPrecision(int& precision)
+ inline void CheckPrecisionRange(int& precision)
{
int error_code = 0;
- CheckPrecision(precision, error_code);
+ CheckPrecisionRange(precision, error_code);
+ }
+
+ inline int TriSign(int64_t x) // returns 0, 1 or -1
+ {
+ return (x > 0) - (x < 0);
+ }
+
+ struct MultiplyUInt64Result
+ {
+ const uint64_t result = 0;
+ const uint64_t carry = 0;
+
+ bool operator==(const MultiplyUInt64Result& other) const
+ {
+ return result == other.result && carry == other.carry;
+ };
+ };
+
+ inline MultiplyUInt64Result Multiply(uint64_t a, uint64_t b) // #834, #835
+ {
+ const auto lo = [](uint64_t x) { return x & 0xFFFFFFFF; };
+ const auto hi = [](uint64_t x) { return x >> 32; };
+
+ const uint64_t x1 = lo(a) * lo(b);
+ const uint64_t x2 = hi(a) * lo(b) + hi(x1);
+ const uint64_t x3 = lo(a) * hi(b) + lo(x2);
+ const uint64_t result = lo(x3) << 32 | lo(x1);
+ const uint64_t carry = hi(a) * hi(b) + hi(x2) + hi(x3);
+
+ return { result, carry };
+ }
+
+ // returns true if (and only if) a * b == c * d
+ inline bool ProductsAreEqual(int64_t a, int64_t b, int64_t c, int64_t d)
+ {
+// -- GODOT start --
+// #if (defined(__clang__) || defined(__GNUC__)) && UINTPTR_MAX >= UINT64_MAX
+// const auto ab = static_cast<__int128_t>(a) * static_cast<__int128_t>(b);
+// const auto cd = static_cast<__int128_t>(c) * static_cast<__int128_t>(d);
+// return ab == cd;
+// #else
+// -- GODOT end --
+ // nb: unsigned values needed for calculating overflow carry
+ const auto abs_a = static_cast<uint64_t>(std::abs(a));
+ const auto abs_b = static_cast<uint64_t>(std::abs(b));
+ const auto abs_c = static_cast<uint64_t>(std::abs(c));
+ const auto abs_d = static_cast<uint64_t>(std::abs(d));
+
+ const auto abs_ab = Multiply(abs_a, abs_b);
+ const auto abs_cd = Multiply(abs_c, abs_d);
+
+ // nb: it's important to differentiate 0 values here from other values
+ const auto sign_ab = TriSign(a) * TriSign(b);
+ const auto sign_cd = TriSign(c) * TriSign(d);
+
+ return abs_ab == abs_cd && sign_ab == sign_cd;
+// -- GODOT start --
+// #endif
+// -- GODOT end --
+ }
+
+ template <typename T>
+ inline bool IsCollinear(const Point<T>& pt1,
+ const Point<T>& sharedPt, const Point<T>& pt2) // #777
+ {
+ const auto a = sharedPt.x - pt1.x;
+ const auto b = pt2.y - sharedPt.y;
+ const auto c = sharedPt.y - pt1.y;
+ const auto d = pt2.x - sharedPt.x;
+ // When checking for collinearity with very large coordinate values
+ // then ProductsAreEqual is more accurate than using CrossProduct.
+ return ProductsAreEqual(a, b, c, d);
}
+
template <typename T>
inline double CrossProduct(const Point<T>& pt1, const Point<T>& pt2, const Point<T>& pt3) {
return (static_cast<double>(pt2.x - pt1.x) * static_cast<double>(pt3.y -
@@ -635,15 +766,17 @@ namespace Clipper2Lib
}
template <typename T>
- inline double DistanceFromLineSqrd(const Point<T>& pt, const Point<T>& ln1, const Point<T>& ln2)
+ inline double PerpendicDistFromLineSqrd(const Point<T>& pt,
+ const Point<T>& line1, const Point<T>& line2)
{
//perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²)
//see http://en.wikipedia.org/wiki/Perpendicular_distance
- double A = static_cast<double>(ln1.y - ln2.y);
- double B = static_cast<double>(ln2.x - ln1.x);
- double C = A * ln1.x + B * ln1.y;
- C = A * pt.x + B * pt.y - C;
- return (C * C) / (A * A + B * B);
+ double a = static_cast<double>(pt.x - line1.x);
+ double b = static_cast<double>(pt.y - line1.y);
+ double c = static_cast<double>(line2.x - line1.x);
+ double d = static_cast<double>(line2.y - line1.y);
+ if (c == 0 && d == 0) return 0;
+ return Sqr(a * d - c * b) / (c * c + d * d);
}
template <typename T>
@@ -663,7 +796,7 @@ namespace Clipper2Lib
}
if (cnt & 1)
a += static_cast<double>(it2->y + it1->y) * (it2->x - it1->x);
- return a * 0.5;
+ return (a * 0.5);
}
template <typename T>
@@ -681,16 +814,73 @@ namespace Clipper2Lib
template <typename T>
inline bool IsPositive(const Path<T>& poly)
{
- // A curve has positive orientation [and area] if a region 'R'
+ // A curve has positive orientation [and area] if a region 'R'
// is on the left when traveling around the outside of 'R'.
//https://mathworld.wolfram.com/CurveOrientation.html
//nb: This statement is premised on using Cartesian coordinates
return Area<T>(poly) >= 0;
}
-
- inline bool GetIntersectPoint(const Point64& ln1a, const Point64& ln1b,
- const Point64& ln2a, const Point64& ln2b, Point64& ip)
- {
+
+#if CLIPPER2_HI_PRECISION
+ // caution: this will compromise performance
+ // https://github.com/AngusJohnson/Clipper2/issues/317#issuecomment-1314023253
+ // See also CPP/BenchMark/GetIntersectPtBenchmark.cpp
+ #define CC_MIN(x,y) ((x)>(y)?(y):(x))
+ #define CC_MAX(x,y) ((x)<(y)?(y):(x))
+ template<typename T>
+ inline bool GetSegmentIntersectPt(const Point<T>& ln1a, const Point<T>& ln1b,
+ const Point<T>& ln2a, const Point<T>& ln2b, Point<T>& ip)
+ {
+ double ln1dy = static_cast<double>(ln1b.y - ln1a.y);
+ double ln1dx = static_cast<double>(ln1a.x - ln1b.x);
+ double ln2dy = static_cast<double>(ln2b.y - ln2a.y);
+ double ln2dx = static_cast<double>(ln2a.x - ln2b.x);
+ double det = (ln2dy * ln1dx) - (ln1dy * ln2dx);
+ if (det == 0.0) return false;
+ T bb0minx = CC_MIN(ln1a.x, ln1b.x);
+ T bb0miny = CC_MIN(ln1a.y, ln1b.y);
+ T bb0maxx = CC_MAX(ln1a.x, ln1b.x);
+ T bb0maxy = CC_MAX(ln1a.y, ln1b.y);
+ T bb1minx = CC_MIN(ln2a.x, ln2b.x);
+ T bb1miny = CC_MIN(ln2a.y, ln2b.y);
+ T bb1maxx = CC_MAX(ln2a.x, ln2b.x);
+ T bb1maxy = CC_MAX(ln2a.y, ln2b.y);
+
+ if constexpr (std::is_integral_v<T>)
+ {
+ int64_t originx = (CC_MIN(bb0maxx, bb1maxx) + CC_MAX(bb0minx, bb1minx)) >> 1;
+ int64_t originy = (CC_MIN(bb0maxy, bb1maxy) + CC_MAX(bb0miny, bb1miny)) >> 1;
+ double ln0c = (ln1dy * static_cast<double>(ln1a.x - originx)) +
+ (ln1dx * static_cast<double>(ln1a.y - originy));
+ double ln1c = (ln2dy * static_cast<double>(ln2a.x - originx)) +
+ (ln2dx * static_cast<double>(ln2a.y - originy));
+ double hitx = ((ln1dx * ln1c) - (ln2dx * ln0c)) / det;
+ double hity = ((ln2dy * ln0c) - (ln1dy * ln1c)) / det;
+
+ ip.x = originx + (T)nearbyint(hitx);
+ ip.y = originy + (T)nearbyint(hity);
+ }
+ else
+ {
+ double originx = (CC_MIN(bb0maxx, bb1maxx) + CC_MAX(bb0minx, bb1minx)) / 2.0;
+ double originy = (CC_MIN(bb0maxy, bb1maxy) + CC_MAX(bb0miny, bb1miny)) / 2.0;
+ double ln0c = (ln1dy * static_cast<double>(ln1a.x - originx)) +
+ (ln1dx * static_cast<double>(ln1a.y - originy));
+ double ln1c = (ln2dy * static_cast<double>(ln2a.x - originx)) +
+ (ln2dx * static_cast<double>(ln2a.y - originy));
+ double hitx = ((ln1dx * ln1c) - (ln2dx * ln0c)) / det;
+ double hity = ((ln2dy * ln0c) - (ln1dy * ln1c)) / det;
+
+ ip.x = originx + static_cast<T>(hitx);
+ ip.y = originy + static_cast<T>(hity);
+ }
+ return true;
+}
+#else
+ template<typename T>
+ inline bool GetSegmentIntersectPt(const Point<T>& ln1a, const Point<T>& ln1b,
+ const Point<T>& ln2a, const Point<T>& ln2b, Point<T>& ip)
+ {
// https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
double dx1 = static_cast<double>(ln1b.x - ln1a.x);
double dy1 = static_cast<double>(ln1b.y - ln1a.y);
@@ -700,15 +890,44 @@ namespace Clipper2Lib
double det = dy1 * dx2 - dy2 * dx1;
if (det == 0.0) return false;
double t = ((ln1a.x - ln2a.x) * dy2 - (ln1a.y - ln2a.y) * dx2) / det;
- if (t <= 0.0) ip = ln1a; // ?? check further (see also #568)
- else if (t >= 1.0) ip = ln1b; // ?? check further
+ if (t <= 0.0) ip = ln1a;
+ else if (t >= 1.0) ip = ln1b;
else
{
- ip.x = static_cast<int64_t>(ln1a.x + t * dx1);
- ip.y = static_cast<int64_t>(ln1a.y + t * dy1);
- }
+ ip.x = static_cast<T>(ln1a.x + t * dx1);
+ ip.y = static_cast<T>(ln1a.y + t * dy1);
+ }
return true;
}
+#endif
+
+ template<typename T>
+ inline Point<T> TranslatePoint(const Point<T>& pt, double dx, double dy)
+ {
+#ifdef USINGZ
+ return Point<T>(pt.x + dx, pt.y + dy, pt.z);
+#else
+ return Point<T>(pt.x + dx, pt.y + dy);
+#endif
+ }
+
+
+ template<typename T>
+ inline Point<T> ReflectPoint(const Point<T>& pt, const Point<T>& pivot)
+ {
+#ifdef USINGZ
+ return Point<T>(pivot.x + (pivot.x - pt.x), pivot.y + (pivot.y - pt.y), pt.z);
+#else
+ return Point<T>(pivot.x + (pivot.x - pt.x), pivot.y + (pivot.y - pt.y));
+#endif
+ }
+
+ template<typename T>
+ inline int GetSign(const T& val)
+ {
+ if (!val) return 0;
+ return (val > 0) ? 1 : -1;
+ }
inline bool SegmentsIntersect(const Point64& seg1a, const Point64& seg1b,
const Point64& seg2a, const Point64& seg2b, bool inclusive = false)
@@ -724,10 +943,10 @@ namespace Clipper2Lib
return (res1 || res2 || res3 || res4); // ensures not collinear
}
else {
- return (CrossProduct(seg1a, seg2a, seg2b) *
- CrossProduct(seg1b, seg2a, seg2b) < 0) &&
- (CrossProduct(seg2a, seg1a, seg1b) *
- CrossProduct(seg2b, seg1a, seg1b) < 0);
+ return (GetSign(CrossProduct(seg1a, seg2a, seg2b)) *
+ GetSign(CrossProduct(seg1b, seg2a, seg2b)) < 0) &&
+ (GetSign(CrossProduct(seg2a, seg1a, seg1b)) *
+ GetSign(CrossProduct(seg2b, seg1a, seg1b)) < 0);
}
}
@@ -743,7 +962,7 @@ namespace Clipper2Lib
static_cast<double>(offPt.y - seg1.y) * dy) /
(Sqr(dx) + Sqr(dy));
if (q < 0) q = 0; else if (q > 1) q = 1;
- if constexpr (std::numeric_limits<T>::is_integer)
+ if constexpr (std::is_integral_v<T>)
return Point<T>(
seg1.x + static_cast<T>(nearbyint(q * dx)),
seg1.y + static_cast<T>(nearbyint(q * dy)));
@@ -770,7 +989,7 @@ namespace Clipper2Lib
return PointInPolygonResult::IsOutside;
bool is_above = first->y < pt.y, starting_above = is_above;
- curr = first +1;
+ curr = first +1;
while (true)
{
if (curr == cend)
@@ -779,7 +998,7 @@ namespace Clipper2Lib
cend = first;
curr = cbegin;
}
-
+
if (is_above)
{
while (curr != cend && curr->y < pt.y) ++curr;
@@ -791,14 +1010,14 @@ namespace Clipper2Lib
if (curr == cend) continue;
}
- if (curr == cbegin)
+ if (curr == cbegin)
prev = polygon.cend() - 1; //nb: NOT cend (since might equal first)
- else
+ else
prev = curr - 1;
if (curr->y == pt.y)
{
- if (curr->x == pt.x ||
+ if (curr->x == pt.x ||
(curr->y == prev->y &&
((pt.x < prev->x) != (pt.x < curr->x))))
return PointInPolygonResult::IsOn;
@@ -822,7 +1041,7 @@ namespace Clipper2Lib
is_above = !is_above;
++curr;
}
-
+
if (is_above != starting_above)
{
cend = polygon.cend();
diff --git a/thirdparty/clipper2/include/clipper2/clipper.engine.h b/thirdparty/clipper2/include/clipper2/clipper.engine.h
index 13c7f069aa..f6108832cd 100644
--- a/thirdparty/clipper2/include/clipper2/clipper.engine.h
+++ b/thirdparty/clipper2/include/clipper2/clipper.engine.h
@@ -1,8 +1,8 @@
/*******************************************************************************
* Author : Angus Johnson *
-* Date : 22 November 2023 *
+* Date : 5 July 2024 *
* Website : http://www.angusj.com *
-* Copyright : Angus Johnson 2010-2023 *
+* Copyright : Angus Johnson 2010-2024 *
* Purpose : This is the main polygon clipping module *
* License : http://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************/
@@ -33,7 +33,7 @@ namespace Clipper2Lib {
//Note: all clipping operations except for Difference are commutative.
enum class ClipType { None, Intersection, Union, Difference, Xor };
-
+
enum class PathType { Subject, Clip };
enum class JoinWith { None, Left, Right };
@@ -41,7 +41,7 @@ namespace Clipper2Lib {
None = 0, OpenStart = 1, OpenEnd = 2, LocalMax = 4, LocalMin = 8
};
- constexpr enum VertexFlags operator &(enum VertexFlags a, enum VertexFlags b)
+ constexpr enum VertexFlags operator &(enum VertexFlags a, enum VertexFlags b)
{
return (enum VertexFlags)(uint32_t(a) & uint32_t(b));
}
@@ -95,7 +95,7 @@ namespace Clipper2Lib {
Path64 path;
bool is_open = false;
- ~OutRec() {
+ ~OutRec() {
if (splits) delete splits;
// nb: don't delete the split pointers
// as these are owned by ClipperBase's outrec_list_
@@ -106,7 +106,7 @@ namespace Clipper2Lib {
//Important: UP and DOWN here are premised on Y-axis positive down
//displays, which is the orientation used in Clipper's development.
///////////////////////////////////////////////////////////////////
-
+
struct Active {
Point64 bot;
Point64 top;
@@ -230,7 +230,7 @@ namespace Clipper2Lib {
inline bool PopHorz(Active *&e);
inline OutPt* StartOpenPath(Active &e, const Point64& pt);
inline void UpdateEdgeIntoAEL(Active *e);
- OutPt* IntersectEdges(Active &e1, Active &e2, const Point64& pt);
+ void IntersectEdges(Active &e1, Active &e2, const Point64& pt);
inline void DeleteFromAEL(Active &e);
inline void AdjustCurrXAndCopyToSEL(const int64_t top_y);
void DoIntersections(const int64_t top_y);
@@ -240,7 +240,7 @@ namespace Clipper2Lib {
void SwapPositionsInAEL(Active& edge1, Active& edge2);
OutRec* NewOutRec();
OutPt* AddOutPt(const Active &e, const Point64& pt);
- OutPt* AddLocalMinPoly(Active &e1, Active &e2,
+ OutPt* AddLocalMinPoly(Active &e1, Active &e2,
const Point64& pt, bool is_new = false);
OutPt* AddLocalMaxPoly(Active &e1, Active &e2, const Point64& pt);
void DoHorizontal(Active &horz);
@@ -251,13 +251,13 @@ namespace Clipper2Lib {
void JoinOutrecPaths(Active &e1, Active &e2);
void FixSelfIntersects(OutRec* outrec);
void DoSplitOp(OutRec* outRec, OutPt* splitOp);
-
+
inline void AddTrialHorzJoin(OutPt* op);
void ConvertHorzSegsToJoins();
void ProcessHorzJoins();
void Split(Active& e, const Point64& pt);
- inline void CheckJoinLeft(Active& e,
+ inline void CheckJoinLeft(Active& e,
const Point64& pt, bool check_curr_x = false);
inline void CheckJoinRight(Active& e,
const Point64& pt, bool check_curr_x = false);
@@ -326,12 +326,12 @@ namespace Clipper2Lib {
const PolyPath* Parent() const { return parent_; }
- bool IsHole() const
+ bool IsHole() const
{
unsigned lvl = Level();
//Even levels except level 0
return lvl && !(lvl & 1);
- }
+ }
};
typedef typename std::vector<std::unique_ptr<PolyPath64>> PolyPath64List;
@@ -343,15 +343,16 @@ namespace Clipper2Lib {
Path64 polygon_;
public:
explicit PolyPath64(PolyPath64* parent = nullptr) : PolyPath(parent) {}
+ explicit PolyPath64(PolyPath64* parent, const Path64& path) : PolyPath(parent) { polygon_ = path; }
~PolyPath64() {
childs_.resize(0);
}
PolyPath64* operator [] (size_t index) const
- {
+ {
return childs_[index].get(); //std::unique_ptr
- }
+ }
PolyPath64* Child(size_t index) const
{
@@ -363,10 +364,7 @@ namespace Clipper2Lib {
PolyPath64* AddChild(const Path64& path) override
{
- auto p = std::make_unique<PolyPath64>(this);
- auto* result = childs_.emplace_back(std::move(p)).get();
- result->polygon_ = path;
- return result;
+ return childs_.emplace_back(std::make_unique<PolyPath64>(this, path)).get();
}
void Clear() override
@@ -401,12 +399,25 @@ namespace Clipper2Lib {
scale_ = parent ? parent->scale_ : 1.0;
}
+ explicit PolyPathD(PolyPathD* parent, const Path64& path) : PolyPath(parent)
+ {
+ scale_ = parent ? parent->scale_ : 1.0;
+ int error_code = 0;
+ polygon_ = ScalePath<double, int64_t>(path, scale_, error_code);
+ }
+
+ explicit PolyPathD(PolyPathD* parent, const PathD& path) : PolyPath(parent)
+ {
+ scale_ = parent ? parent->scale_ : 1.0;
+ polygon_ = path;
+ }
+
~PolyPathD() {
childs_.resize(0);
}
PolyPathD* operator [] (size_t index) const
- {
+ {
return childs_[index].get();
}
@@ -420,22 +431,15 @@ namespace Clipper2Lib {
void SetScale(double value) { scale_ = value; }
double Scale() const { return scale_; }
-
+
PolyPathD* AddChild(const Path64& path) override
{
- int error_code = 0;
- auto p = std::make_unique<PolyPathD>(this);
- PolyPathD* result = childs_.emplace_back(std::move(p)).get();
- result->polygon_ = ScalePath<double, int64_t>(path, scale_, error_code);
- return result;
+ return childs_.emplace_back(std::make_unique<PolyPathD>(this, path)).get();
}
PolyPathD* AddChild(const PathD& path)
{
- auto p = std::make_unique<PolyPathD>(this);
- PolyPathD* result = childs_.emplace_back(std::move(p)).get();
- result->polygon_ = path;
- return result;
+ return childs_.emplace_back(std::make_unique<PolyPathD>(this, path)).get();
}
void Clear() override
@@ -488,7 +492,7 @@ namespace Clipper2Lib {
return Execute(clip_type, fill_rule, closed_paths, dummy);
}
- bool Execute(ClipType clip_type, FillRule fill_rule,
+ bool Execute(ClipType clip_type, FillRule fill_rule,
Paths64& closed_paths, Paths64& open_paths)
{
closed_paths.clear();
@@ -530,7 +534,7 @@ namespace Clipper2Lib {
public:
explicit ClipperD(int precision = 2) : ClipperBase()
{
- CheckPrecision(precision, error_code_);
+ CheckPrecisionRange(precision, error_code_);
// to optimize scaling / descaling precision
// set the scale to a power of double's radix (2) (#25)
scale_ = std::pow(std::numeric_limits<double>::radix,
@@ -560,12 +564,12 @@ namespace Clipper2Lib {
void CheckCallback()
{
if(zCallbackD_)
- // if the user defined float point callback has been assigned
+ // if the user defined float point callback has been assigned
// then assign the proxy callback function
- ClipperBase::zCallback_ =
+ ClipperBase::zCallback_ =
std::bind(&ClipperD::ZCB, this, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_3,
- std::placeholders::_4, std::placeholders::_5);
+ std::placeholders::_4, std::placeholders::_5);
else
ClipperBase::zCallback_ = nullptr;
}
@@ -632,6 +636,6 @@ namespace Clipper2Lib {
};
-} // namespace
+} // namespace
#endif // CLIPPER_ENGINE_H
diff --git a/thirdparty/clipper2/include/clipper2/clipper.export.h b/thirdparty/clipper2/include/clipper2/clipper.export.h
index d7286132a4..53a445368e 100644
--- a/thirdparty/clipper2/include/clipper2/clipper.export.h
+++ b/thirdparty/clipper2/include/clipper2/clipper.export.h
@@ -1,14 +1,14 @@
/*******************************************************************************
* Author : Angus Johnson *
-* Date : 26 November 2023 *
+* Date : 14 May 2024 *
* Website : http://www.angusj.com *
-* Copyright : Angus Johnson 2010-2023 *
+* Copyright : Angus Johnson 2010-2024 *
* Purpose : This module exports the Clipper2 Library (ie DLL/so) *
* License : http://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************/
-/*
+/*
Boolean clipping:
cliptype: None=0, Intersection=1, Union=2, Difference=3, Xor=4
fillrule: EvenOdd=0, NonZero=1, Positive=2, Negative=3
@@ -19,12 +19,12 @@
The path structures used extensively in other parts of this library are all
based on std::vector classes. Since C++ classes can't be accessed by other
-languages, these paths must be converted into simple C data structures that
-can be understood by just about any programming language. And these C style
-path structures are simple arrays of int64_t (CPath64) and double (CPathD).
+languages, these paths are converted into very simple array data structures
+(of either int64_t for CPath64 or double for CPathD) that can be parsed by
+just about any programming language.
CPath64 and CPathD:
-These are arrays of consecutive x and y path coordinates preceeded by
+These are arrays of consecutive x and y path coordinates preceeded by
a pair of values containing the path's length (N) and a 0 value.
__________________________________
|counter|coord1|coord2|...|coordN|
@@ -34,23 +34,24 @@ __________________________________
CPaths64 and CPathsD:
These are also arrays containing any number of consecutive CPath64 or
CPathD structures. But preceeding these consecutive paths, there is pair of
-values that contain the total length of the array (A) structure and
-the number (C) of CPath64 or CPathD it contains.
+values that contain the total length of the array structure (A) and the
+number of CPath64 or CPathD it contains (C). The space these structures will
+occupy in memory = A * sizeof(int64_t) or A * sizeof(double) respectively.
_______________________________
|counter|path1|path2|...|pathC|
|A , C | |
_______________________________
CPolytree64 and CPolytreeD:
-These are also arrays consisting of CPolyPath structures that represent
+These are also arrays consisting of CPolyPath structures that represent
individual paths in a tree structure. However, the very first (ie top)
-CPolyPath is just the tree container that won't have a path. And because
+CPolyPath is just the tree container that doesn't have a path. And because
of that, its structure will be very slightly different from the remaining
CPolyPath. This difference will be discussed below.
CPolyPath64 and CPolyPathD:
-These are simple arrays consisting of a series of path coordinates followed
-by any number of child (ie nested) CPolyPath. Preceeding these are two values
+These are simple arrays consisting of a series of path coordinates followed
+by any number of child (ie nested) CPolyPath. Preceeding these are two values
indicating the length of the path (N) and the number of child CPolyPath (C).
____________________________________________________________
|counter|coord1|coord2|...|coordN| child1|child2|...|childC|
@@ -58,19 +59,20 @@ ____________________________________________________________
____________________________________________________________
As mentioned above, the very first CPolyPath structure is just a container
-that owns (both directly and indirectly) every other CPolyPath in the tree.
+that owns (both directly and indirectly) every other CPolyPath in the tree.
Since this first CPolyPath has no path, instead of a path length, its very
-first value will contain the total length of the CPolytree array structure.
-
-All theses exported structures (CPaths64, CPathsD, CPolyTree64 & CPolyTreeD)
-are arrays of type int64_t or double. And the first value in these arrays
-will always contain the length of that array.
-
-These array structures are allocated in heap memory which will eventually
-need to be released. But since applications dynamically linking to these
-functions may use different memory managers, the only safe way to free up
-this memory is to use the exported DisposeArray64 and DisposeArrayD
-functions below.
+first value will contain the total length of the CPolytree array (not its
+total bytes length).
+
+Again, all theses exported structures (CPaths64, CPathsD, CPolyTree64 &
+CPolyTreeD) are arrays of either type int64_t or double, and the first
+value in these arrays will always be the length of that array.
+
+These array structures are allocated in heap memory which will eventually
+need to be released. However, since applications dynamically linking to
+these functions may use different memory managers, the only safe way to
+free up this memory is to use the exported DisposeArray64 and
+DisposeArrayD functions (see below).
*/
@@ -128,7 +130,7 @@ inline Rect<T> CRectToRect(const CRect<T>& rect)
#ifdef _WIN32
#define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport)
#else
- #define EXTERN_DLL_EXPORT extern "C"
+ #define EXTERN_DLL_EXPORT extern "C"
#endif
@@ -173,8 +175,8 @@ EXTERN_DLL_EXPORT int BooleanOp_PolyTreeD(uint8_t cliptype,
bool preserve_collinear = true, bool reverse_solution = false);
EXTERN_DLL_EXPORT CPaths64 InflatePaths64(const CPaths64 paths,
- double delta, uint8_t jointype, uint8_t endtype,
- double miter_limit = 2.0, double arc_tolerance = 0.0,
+ double delta, uint8_t jointype, uint8_t endtype,
+ double miter_limit = 2.0, double arc_tolerance = 0.0,
bool reverse_solution = false);
EXTERN_DLL_EXPORT CPathsD InflatePathsD(const CPathsD paths,
double delta, uint8_t jointype, uint8_t endtype,
@@ -219,10 +221,10 @@ static size_t GetPolyPath64ArrayLen(const PolyPath64& pp)
return result;
}
-static void GetPolytreeCountAndCStorageSize(const PolyTree64& tree,
+static void GetPolytreeCountAndCStorageSize(const PolyTree64& tree,
size_t& cnt, size_t& array_len)
{
- cnt = tree.Count(); // nb: top level count only
+ cnt = tree.Count(); // nb: top level count only
array_len = GetPolyPath64ArrayLen(tree);
}
@@ -272,16 +274,33 @@ CPathsD CreateCPathsDFromPaths64(const Paths64& paths, double scale)
}
template <typename T>
+static Path<T> ConvertCPath(T* path)
+{
+ Path<T> result;
+ if (!path) return result;
+ T* v = path;
+ size_t cnt = static_cast<size_t>(*v);
+ v += 2; // skip 0 value
+ result.reserve(cnt);
+ for (size_t j = 0; j < cnt; ++j)
+ {
+ T x = *v++, y = *v++;
+ result.push_back(Point<T>(x, y));
+ }
+ return result;
+}
+
+template <typename T>
static Paths<T> ConvertCPaths(T* paths)
{
Paths<T> result;
if (!paths) return result;
T* v = paths; ++v;
- size_t cnt = *v++;
+ size_t cnt = static_cast<size_t>(*v++);
result.reserve(cnt);
for (size_t i = 0; i < cnt; ++i)
{
- size_t cnt2 = *v;
+ size_t cnt2 = static_cast<size_t>(*v);
v += 2;
Path<T> path;
path.reserve(cnt2);
@@ -300,17 +319,17 @@ static Paths64 ConvertCPathsDToPaths64(const CPathsD paths, double scale)
{
Paths64 result;
if (!paths) return result;
- double* v = paths;
+ double* v = paths;
++v; // skip the first value (0)
- int64_t cnt = (int64_t)*v++;
+ size_t cnt = static_cast<size_t>(*v++);
result.reserve(cnt);
- for (int i = 0; i < cnt; ++i)
+ for (size_t i = 0; i < cnt; ++i)
{
- int64_t cnt2 = (int64_t)*v;
+ size_t cnt2 = static_cast<size_t>(*v);
v += 2;
Path64 path;
path.reserve(cnt2);
- for (int j = 0; j < cnt2; ++j)
+ for (size_t j = 0; j < cnt2; ++j)
{
double x = *v++ * scale;
double y = *v++ * scale;
@@ -362,7 +381,7 @@ EXTERN_DLL_EXPORT const char* Version()
return CLIPPER2_VERSION;
}
-EXTERN_DLL_EXPORT int BooleanOp64(uint8_t cliptype,
+EXTERN_DLL_EXPORT int BooleanOp64(uint8_t cliptype,
uint8_t fillrule, const CPaths64 subjects,
const CPaths64 subjects_open, const CPaths64 clips,
CPaths64& solution, CPaths64& solution_open,
@@ -370,7 +389,7 @@ EXTERN_DLL_EXPORT int BooleanOp64(uint8_t cliptype,
{
if (cliptype > static_cast<uint8_t>(ClipType::Xor)) return -4;
if (fillrule > static_cast<uint8_t>(FillRule::Negative)) return -3;
-
+
Paths64 sub, sub_open, clp, sol, sol_open;
sub = ConvertCPaths(subjects);
sub_open = ConvertCPaths(subjects_open);
@@ -382,7 +401,7 @@ EXTERN_DLL_EXPORT int BooleanOp64(uint8_t cliptype,
if (sub.size() > 0) clipper.AddSubject(sub);
if (sub_open.size() > 0) clipper.AddOpenSubject(sub_open);
if (clp.size() > 0) clipper.AddClip(clp);
- if (!clipper.Execute(ClipType(cliptype), FillRule(fillrule), sol, sol_open))
+ if (!clipper.Execute(ClipType(cliptype), FillRule(fillrule), sol, sol_open))
return -1; // clipping bug - should never happen :)
solution = CreateCPaths(sol);
solution_open = CreateCPaths(sol_open);
@@ -455,7 +474,7 @@ EXTERN_DLL_EXPORT int BooleanOp_PolyTreeD(uint8_t cliptype,
if (precision < -8 || precision > 8) return -5;
if (cliptype > static_cast<uint8_t>(ClipType::Xor)) return -4;
if (fillrule > static_cast<uint8_t>(FillRule::Negative)) return -3;
-
+
double scale = std::pow(10, precision);
int err = 0;
@@ -485,10 +504,10 @@ EXTERN_DLL_EXPORT CPaths64 InflatePaths64(const CPaths64 paths,
{
Paths64 pp;
pp = ConvertCPaths(paths);
- ClipperOffset clip_offset( miter_limit,
+ ClipperOffset clip_offset( miter_limit,
arc_tolerance, reverse_solution);
clip_offset.AddPaths(pp, JoinType(jointype), EndType(endtype));
- Paths64 result;
+ Paths64 result;
clip_offset.Execute(delta, result);
return CreateCPaths(result);
}
@@ -560,6 +579,22 @@ EXTERN_DLL_EXPORT CPathsD RectClipLinesD(const CRectD& rect,
return CreateCPathsDFromPaths64(result, 1 / scale);
}
+EXTERN_DLL_EXPORT CPaths64 MinkowskiSum64(const CPath64& cpattern, const CPath64& cpath, bool is_closed)
+{
+ Path64 path = ConvertCPath(cpath);
+ Path64 pattern = ConvertCPath(cpattern);
+ Paths64 solution = MinkowskiSum(pattern, path, is_closed);
+ return CreateCPaths(solution);
+}
+
+EXTERN_DLL_EXPORT CPaths64 MinkowskiDiff64(const CPath64& cpattern, const CPath64& cpath, bool is_closed)
+{
+ Path64 path = ConvertCPath(cpath);
+ Path64 pattern = ConvertCPath(cpattern);
+ Paths64 solution = MinkowskiDiff(pattern, path, is_closed);
+ return CreateCPaths(solution);
+}
+
} // end Clipper2Lib namespace
-
+
#endif // CLIPPER2_EXPORT_H
diff --git a/thirdparty/clipper2/include/clipper2/clipper.h b/thirdparty/clipper2/include/clipper2/clipper.h
index 0f516b60e8..a2fe5c3cc2 100644
--- a/thirdparty/clipper2/include/clipper2/clipper.h
+++ b/thirdparty/clipper2/include/clipper2/clipper.h
@@ -1,8 +1,8 @@
/*******************************************************************************
* Author : Angus Johnson *
-* Date : 18 November 2023 *
+* Date : 27 April 2024 *
* Website : http://www.angusj.com *
-* Copyright : Angus Johnson 2010-2023 *
+* Copyright : Angus Johnson 2010-2024 *
* Purpose : This module provides a simple interface to the Clipper Library *
* License : http://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************/
@@ -24,7 +24,7 @@ namespace Clipper2Lib {
inline Paths64 BooleanOp(ClipType cliptype, FillRule fillrule,
const Paths64& subjects, const Paths64& clips)
- {
+ {
Paths64 result;
Clipper64 clipper;
clipper.AddSubject(subjects);
@@ -47,7 +47,7 @@ namespace Clipper2Lib {
const PathsD& subjects, const PathsD& clips, int precision = 2)
{
int error_code = 0;
- CheckPrecision(precision, error_code);
+ CheckPrecisionRange(precision, error_code);
PathsD result;
if (error_code) return result;
ClipperD clipper(precision);
@@ -58,12 +58,12 @@ namespace Clipper2Lib {
}
inline void BooleanOp(ClipType cliptype, FillRule fillrule,
- const PathsD& subjects, const PathsD& clips,
+ const PathsD& subjects, const PathsD& clips,
PolyTreeD& polytree, int precision = 2)
{
polytree.Clear();
int error_code = 0;
- CheckPrecision(precision, error_code);
+ CheckPrecisionRange(precision, error_code);
if (error_code) return;
ClipperD clipper(precision);
clipper.AddSubject(subjects);
@@ -75,7 +75,7 @@ namespace Clipper2Lib {
{
return BooleanOp(ClipType::Intersection, fillrule, subjects, clips);
}
-
+
inline PathsD Intersect(const PathsD& subjects, const PathsD& clips, FillRule fillrule, int decimal_prec = 2)
{
return BooleanOp(ClipType::Intersection, fillrule, subjects, clips, decimal_prec);
@@ -104,7 +104,7 @@ namespace Clipper2Lib {
{
PathsD result;
int error_code = 0;
- CheckPrecision(precision, error_code);
+ CheckPrecisionRange(precision, error_code);
if (error_code) return result;
ClipperD clipper(precision);
clipper.AddSubject(subjects);
@@ -145,11 +145,11 @@ namespace Clipper2Lib {
}
inline PathsD InflatePaths(const PathsD& paths, double delta,
- JoinType jt, EndType et, double miter_limit = 2.0,
+ JoinType jt, EndType et, double miter_limit = 2.0,
int precision = 2, double arc_tolerance = 0.0)
{
int error_code = 0;
- CheckPrecision(precision, error_code);
+ CheckPrecisionRange(precision, error_code);
if (!delta) return paths;
if (error_code) return PathsD();
const double scale = std::pow(10, precision);
@@ -219,13 +219,13 @@ namespace Clipper2Lib {
{
if (rect.IsEmpty() || paths.empty()) return PathsD();
int error_code = 0;
- CheckPrecision(precision, error_code);
+ CheckPrecisionRange(precision, error_code);
if (error_code) return PathsD();
const double scale = std::pow(10, precision);
Rect64 r = ScaleRect<int64_t, double>(rect, scale);
RectClip64 rc(r);
Paths64 pp = ScalePaths<int64_t, double>(paths, scale, error_code);
- if (error_code) return PathsD(); // ie: error_code result is lost
+ if (error_code) return PathsD(); // ie: error_code result is lost
return ScalePaths<double, int64_t>(
rc.Execute(pp), 1 / scale, error_code);
}
@@ -251,7 +251,7 @@ namespace Clipper2Lib {
{
if (rect.IsEmpty() || lines.empty()) return PathsD();
int error_code = 0;
- CheckPrecision(precision, error_code);
+ CheckPrecisionRange(precision, error_code);
if (error_code) return PathsD();
const double scale = std::pow(10, precision);
Rect64 r = ScaleRect<int64_t, double>(rect, scale);
@@ -290,8 +290,8 @@ namespace Clipper2Lib {
{
// return false if this child isn't fully contained by its parent
- // checking for a single vertex outside is a bit too crude since
- // it doesn't account for rounding errors. It's better to check
+ // checking for a single vertex outside is a bit too crude since
+ // it doesn't account for rounding errors. It's better to check
// for consecutive vertices found outside the parent's polygon.
int outsideCnt = 0;
@@ -311,7 +311,7 @@ namespace Clipper2Lib {
return true;
}
- static void OutlinePolyPath(std::ostream& os,
+ static void OutlinePolyPath(std::ostream& os,
size_t idx, bool isHole, size_t count, const std::string& preamble)
{
std::string plural = (count == 1) ? "." : "s.";
@@ -342,19 +342,19 @@ namespace Clipper2Lib {
}
template<typename T, typename U>
- inline constexpr void MakePathGeneric(const T an_array,
+ inline constexpr void MakePathGeneric(const T an_array,
size_t array_size, std::vector<U>& result)
{
result.reserve(array_size / 2);
for (size_t i = 0; i < array_size; i +=2)
#ifdef USINGZ
- result.push_back( U{ an_array[i], an_array[i +1], 0} );
+ result.push_back( U{ an_array[i], an_array[i + 1], 0} );
#else
result.push_back( U{ an_array[i], an_array[i + 1]} );
#endif
}
- } // end details namespace
+ } // end details namespace
inline std::ostream& operator<< (std::ostream& os, const PolyTree64& pp)
{
@@ -398,7 +398,7 @@ namespace Clipper2Lib {
inline bool CheckPolytreeFullyContainsChildren(const PolyTree64& polytree)
{
for (const auto& child : polytree)
- if (child->Count() > 0 &&
+ if (child->Count() > 0 &&
!details::PolyPath64ContainsChildren(*child))
return false;
return true;
@@ -471,7 +471,7 @@ namespace Clipper2Lib {
std::size_t size = N / 3;
Path64 result(size);
for (size_t i = 0; i < size; ++i)
- result[i] = Point64(list[i * 3],
+ result[i] = Point64(list[i * 3],
list[i * 3 + 1], list[i * 3 + 2]);
return result;
}
@@ -489,7 +489,7 @@ namespace Clipper2Lib {
list[i * 3 + 1], list[i * 3 + 2]);
else
for (size_t i = 0; i < size; ++i)
- result[i] = PointD(list[i * 3], list[i * 3 + 1],
+ result[i] = PointD(list[i * 3], list[i * 3 + 1],
static_cast<int64_t>(list[i * 3 + 2]));
return result;
}
@@ -510,9 +510,9 @@ namespace Clipper2Lib {
if (!is_open_path)
{
- while (srcIt != stop && !CrossProduct(*stop, *srcIt, *(srcIt + 1)))
+ while (srcIt != stop && IsCollinear(*stop, *srcIt, *(srcIt + 1)))
++srcIt;
- while (srcIt != stop && !CrossProduct(*(stop - 1), *stop, *srcIt))
+ while (srcIt != stop && IsCollinear(*(stop - 1), *stop, *srcIt))
--stop;
if (srcIt == stop) return Path64();
}
@@ -521,7 +521,7 @@ namespace Clipper2Lib {
dst.push_back(*prevIt);
for (; srcIt != stop; ++srcIt)
{
- if (CrossProduct(*prevIt, *srcIt, *(srcIt + 1)))
+ if (!IsCollinear(*prevIt, *srcIt, *(srcIt + 1)))
{
prevIt = srcIt;
dst.push_back(*prevIt);
@@ -530,12 +530,12 @@ namespace Clipper2Lib {
if (is_open_path)
dst.push_back(*srcIt);
- else if (CrossProduct(*prevIt, *stop, dst[0]))
+ else if (!IsCollinear(*prevIt, *stop, dst[0]))
dst.push_back(*stop);
else
{
while (dst.size() > 2 &&
- !CrossProduct(dst[dst.size() - 1], dst[dst.size() - 2], dst[0]))
+ IsCollinear(dst[dst.size() - 1], dst[dst.size() - 2], dst[0]))
dst.pop_back();
if (dst.size() < 3) return Path64();
}
@@ -545,7 +545,7 @@ namespace Clipper2Lib {
inline PathD TrimCollinear(const PathD& path, int precision, bool is_open_path = false)
{
int error_code = 0;
- CheckPrecision(precision, error_code);
+ CheckPrecisionRange(precision, error_code);
if (error_code) return PathD();
const double scale = std::pow(10, precision);
Path64 p = ScalePath<int64_t, double>(path, scale, error_code);
@@ -580,23 +580,23 @@ namespace Clipper2Lib {
double cp = std::abs(CrossProduct(pt1, pt2, pt3));
return (cp * cp) / (DistanceSqr(pt1, pt2) * DistanceSqr(pt2, pt3)) < sin_sqrd_min_angle_rads;
}
-
+
template <typename T>
- inline Path<T> Ellipse(const Rect<T>& rect, int steps = 0)
+ inline Path<T> Ellipse(const Rect<T>& rect, size_t steps = 0)
{
- return Ellipse(rect.MidPoint(),
- static_cast<double>(rect.Width()) *0.5,
+ return Ellipse(rect.MidPoint(),
+ static_cast<double>(rect.Width()) *0.5,
static_cast<double>(rect.Height()) * 0.5, steps);
}
template <typename T>
inline Path<T> Ellipse(const Point<T>& center,
- double radiusX, double radiusY = 0, int steps = 0)
+ double radiusX, double radiusY = 0, size_t steps = 0)
{
if (radiusX <= 0) return Path<T>();
if (radiusY <= 0) radiusY = radiusX;
if (steps <= 2)
- steps = static_cast<int>(PI * sqrt((radiusX + radiusY) / 2));
+ steps = static_cast<size_t>(PI * sqrt((radiusX + radiusY) / 2));
double si = std::sin(2 * PI / steps);
double co = std::cos(2 * PI / steps);
@@ -604,7 +604,7 @@ namespace Clipper2Lib {
Path<T> result;
result.reserve(steps);
result.push_back(Point<T>(center.x + radiusX, static_cast<double>(center.y)));
- for (int i = 1; i < steps; ++i)
+ for (size_t i = 1; i < steps; ++i)
{
result.push_back(Point<T>(center.x + radiusX * dx, center.y + radiusY * dy));
double x = dx * co - dy * si;
@@ -614,19 +614,7 @@ namespace Clipper2Lib {
return result;
}
- template <typename T>
- inline double PerpendicDistFromLineSqrd(const Point<T>& pt,
- const Point<T>& line1, const Point<T>& line2)
- {
- double a = static_cast<double>(pt.x - line1.x);
- double b = static_cast<double>(pt.y - line1.y);
- double c = static_cast<double>(line2.x - line1.x);
- double d = static_cast<double>(line2.y - line1.y);
- if (c == 0 && d == 0) return 0;
- return Sqr(a * d - c * b) / (c * c + d * d);
- }
-
- inline size_t GetNext(size_t current, size_t high,
+ inline size_t GetNext(size_t current, size_t high,
const std::vector<bool>& flags)
{
++current;
@@ -637,7 +625,7 @@ namespace Clipper2Lib {
return current;
}
- inline size_t GetPrior(size_t current, size_t high,
+ inline size_t GetPrior(size_t current, size_t high,
const std::vector<bool>& flags)
{
if (current == 0) current = high;
@@ -650,7 +638,7 @@ namespace Clipper2Lib {
}
template <typename T>
- inline Path<T> SimplifyPath(const Path<T> &path,
+ inline Path<T> SimplifyPath(const Path<T> &path,
double epsilon, bool isClosedPath = true)
{
const size_t len = path.size(), high = len -1;
@@ -665,7 +653,7 @@ namespace Clipper2Lib {
distSqr[0] = PerpendicDistFromLineSqrd(path[0], path[high], path[1]);
distSqr[high] = PerpendicDistFromLineSqrd(path[high], path[0], path[high - 1]);
}
- else
+ else
{
distSqr[0] = MAX_DBL;
distSqr[high] = MAX_DBL;
@@ -684,7 +672,7 @@ namespace Clipper2Lib {
} while (curr != start && distSqr[curr] > epsSqr);
if (curr == start) break;
}
-
+
prior = GetPrior(curr, high, flags);
next = GetNext(curr, high, flags);
if (next == prior) break;
@@ -699,7 +687,7 @@ namespace Clipper2Lib {
}
else
prior2 = GetPrior(prior, high, flags);
-
+
flags[curr] = true;
curr = next;
next = GetNext(next, high, flags);
@@ -717,7 +705,7 @@ namespace Clipper2Lib {
}
template <typename T>
- inline Paths<T> SimplifyPaths(const Paths<T> &paths,
+ inline Paths<T> SimplifyPaths(const Paths<T> &paths,
double epsilon, bool isClosedPath = true)
{
Paths<T> result;
diff --git a/thirdparty/clipper2/include/clipper2/clipper.minkowski.h b/thirdparty/clipper2/include/clipper2/clipper.minkowski.h
index ebddd08a59..a3ddcf86f3 100644
--- a/thirdparty/clipper2/include/clipper2/clipper.minkowski.h
+++ b/thirdparty/clipper2/include/clipper2/clipper.minkowski.h
@@ -15,7 +15,7 @@
#include <string>
#include "clipper2/clipper.core.h"
-namespace Clipper2Lib
+namespace Clipper2Lib
{
namespace detail
diff --git a/thirdparty/clipper2/include/clipper2/clipper.offset.h b/thirdparty/clipper2/include/clipper2/clipper.offset.h
index 30992bfa55..bb075a6d49 100644
--- a/thirdparty/clipper2/include/clipper2/clipper.offset.h
+++ b/thirdparty/clipper2/include/clipper2/clipper.offset.h
@@ -1,8 +1,8 @@
/*******************************************************************************
* Author : Angus Johnson *
-* Date : 19 November 2023 *
+* Date : 24 March 2024 *
* Website : http://www.angusj.com *
-* Copyright : Angus Johnson 2010-2023 *
+* Copyright : Angus Johnson 2010-2024 *
* Purpose : Path Offset (Inflate/Shrink) *
* License : http://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************/
@@ -34,9 +34,7 @@ private:
class Group {
public:
Paths64 paths_in;
- std::vector<bool> is_hole_list;
- std::vector<Rect64> bounds_list;
- int lowest_path_idx = -1;
+ std::optional<size_t> lowest_path_idx{};
bool is_reversed = false;
JoinType join_type;
EndType end_type;
@@ -52,7 +50,8 @@ private:
double step_cos_ = 0.0;
PathD norms;
Path64 path_out;
- Paths64 solution;
+ Paths64* solution = nullptr;
+ PolyTree64* solution_tree = nullptr;
std::vector<Group> groups_;
JoinType join_type_ = JoinType::Bevel;
EndType end_type_ = EndType::Polygon;
@@ -64,9 +63,10 @@ private:
#ifdef USINGZ
ZCallback64 zCallback64_ = nullptr;
+ void ZCB(const Point64& bot1, const Point64& top1,
+ const Point64& bot2, const Point64& top2, Point64& ip);
#endif
DeltaCallback64 deltaCallback64_ = nullptr;
-
size_t CalcSolutionCapacity();
bool CheckReverseOrientation();
void DoBevel(const Path64& path, size_t j, size_t k);
@@ -83,7 +83,7 @@ private:
public:
explicit ClipperOffset(double miter_limit = 2.0,
double arc_tolerance = 0.0,
- bool preserve_collinear = false,
+ bool preserve_collinear = false,
bool reverse_solution = false) :
miter_limit_(miter_limit), arc_tolerance_(arc_tolerance),
preserve_collinear_(preserve_collinear),
@@ -91,7 +91,7 @@ public:
~ClipperOffset() { Clear(); };
- int ErrorCode() { return error_code_; };
+ int ErrorCode() const { return error_code_; };
void AddPath(const Path64& path, JoinType jt_, EndType et_);
void AddPaths(const Paths64& paths, JoinType jt_, EndType et_);
void Clear() { groups_.clear(); norms.clear(); };
diff --git a/thirdparty/clipper2/include/clipper2/clipper.rectclip.h b/thirdparty/clipper2/include/clipper2/clipper.rectclip.h
index ff043f25f0..bfcfacf2e7 100644
--- a/thirdparty/clipper2/include/clipper2/clipper.rectclip.h
+++ b/thirdparty/clipper2/include/clipper2/clipper.rectclip.h
@@ -1,8 +1,8 @@
/*******************************************************************************
* Author : Angus Johnson *
-* Date : 1 November 2023 *
+* Date : 5 July 2024 *
* Website : http://www.angusj.com *
-* Copyright : Angus Johnson 2010-2023 *
+* Copyright : Angus Johnson 2010-2024 *
* Purpose : FAST rectangular clipping *
* License : http://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************/
@@ -18,6 +18,7 @@
namespace Clipper2Lib
{
+ // Location: the order is important here, see StartLocsIsClockwise()
enum class Location { Left, Top, Right, Bottom, Inside };
class OutPt2;
@@ -26,10 +27,10 @@ namespace Clipper2Lib
class OutPt2 {
public:
Point64 pt;
- size_t owner_idx;
- OutPt2List* edge;
- OutPt2* next;
- OutPt2* prev;
+ size_t owner_idx = 0;
+ OutPt2List* edge = nullptr;
+ OutPt2* next = nullptr;
+ OutPt2* prev = nullptr;
};
//------------------------------------------------------------------------------
@@ -50,9 +51,9 @@ namespace Clipper2Lib
OutPt2List edges_[8]; // clockwise and counter-clockwise
std::vector<Location> start_locs_;
void CheckEdges();
- void TidyEdges(int idx, OutPt2List& cw, OutPt2List& ccw);
+ void TidyEdges(size_t idx, OutPt2List& cw, OutPt2List& ccw);
void GetNextLocation(const Path64& path,
- Location& loc, int& i, int highI);
+ Location& loc, size_t& i, size_t highI);
OutPt2* Add(Point64 pt, bool start_new = false);
void AddCorner(Location prev, Location curr);
void AddCorner(Location& loc, bool isClockwise);
diff --git a/thirdparty/clipper2/include/clipper2/clipper.version.h b/thirdparty/clipper2/include/clipper2/clipper.version.h
index d7644067e2..61464095f6 100644
--- a/thirdparty/clipper2/include/clipper2/clipper.version.h
+++ b/thirdparty/clipper2/include/clipper2/clipper.version.h
@@ -1,6 +1,6 @@
#ifndef CLIPPER_VERSION_H
#define CLIPPER_VERSION_H
-constexpr auto CLIPPER2_VERSION = "1.3.0";
+constexpr auto CLIPPER2_VERSION = "1.4.0";
#endif // CLIPPER_VERSION_H
diff --git a/thirdparty/clipper2/patches/clipper2-exceptions.patch b/thirdparty/clipper2/patches/clipper2-exceptions.patch
index 0e1c6585fe..44c2b0287a 100644
--- a/thirdparty/clipper2/patches/clipper2-exceptions.patch
+++ b/thirdparty/clipper2/patches/clipper2-exceptions.patch
@@ -1,9 +1,9 @@
diff --git a/thirdparty/clipper2/include/clipper2/clipper.core.h b/thirdparty/clipper2/include/clipper2/clipper.core.h
-index b3dddeeaa2..a77cdad5f4 100644
+index 925c04685e..d0d159b949 100644
--- a/thirdparty/clipper2/include/clipper2/clipper.core.h
+++ b/thirdparty/clipper2/include/clipper2/clipper.core.h
-@@ -21,6 +21,8 @@
- #include <numeric>
+@@ -22,6 +22,8 @@
+ #include <optional>
#include "clipper2/clipper.version.h"
+#define CLIPPER2_THROW(exception) std::abort()
@@ -11,7 +11,7 @@ index b3dddeeaa2..a77cdad5f4 100644
namespace Clipper2Lib
{
-@@ -78,18 +80,18 @@ namespace Clipper2Lib
+@@ -79,18 +81,18 @@ namespace Clipper2Lib
switch (error_code)
{
case precision_error_i:
diff --git a/thirdparty/clipper2/patches/gcc14-warning.patch b/thirdparty/clipper2/patches/gcc14-warning.patch
deleted file mode 100644
index a4f06ef37e..0000000000
--- a/thirdparty/clipper2/patches/gcc14-warning.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-diff --git a/thirdparty/clipper2/include/clipper2/clipper.core.h b/thirdparty/clipper2/include/clipper2/clipper.core.h
-index a77cdad5f4..0de7c3720e 100644
---- a/thirdparty/clipper2/include/clipper2/clipper.core.h
-+++ b/thirdparty/clipper2/include/clipper2/clipper.core.h
-@@ -138,7 +138,7 @@ namespace Clipper2Lib
- }
-
- template <typename T2>
-- explicit Point<T>(const Point<T2>& p)
-+ explicit Point(const Point<T2>& p)
- {
- Init(p.x, p.y, p.z);
- }
-@@ -180,7 +180,7 @@ namespace Clipper2Lib
- Point(const T2 x_, const T2 y_) { Init(x_, y_); }
-
- template <typename T2>
-- explicit Point<T>(const Point<T2>& p) { Init(p.x, p.y); }
-+ explicit Point(const Point<T2>& p) { Init(p.x, p.y); }
-
- Point operator * (const double scale) const
- {
diff --git a/thirdparty/clipper2/patches/llvm-error.patch b/thirdparty/clipper2/patches/llvm-error.patch
new file mode 100644
index 0000000000..e326d73e83
--- /dev/null
+++ b/thirdparty/clipper2/patches/llvm-error.patch
@@ -0,0 +1,34 @@
+diff --git a/thirdparty/clipper2/include/clipper2/clipper.core.h b/thirdparty/clipper2/include/clipper2/clipper.core.h
+index 67dd731af6..0f69bf2d9f 100644
+--- a/thirdparty/clipper2/include/clipper2/clipper.core.h
++++ b/thirdparty/clipper2/include/clipper2/clipper.core.h
+@@ -695,11 +695,13 @@ namespace Clipper2Lib
+ // returns true if (and only if) a * b == c * d
+ inline bool ProductsAreEqual(int64_t a, int64_t b, int64_t c, int64_t d)
+ {
+-#if (defined(__clang__) || defined(__GNUC__)) && UINTPTR_MAX >= UINT64_MAX
+- const auto ab = static_cast<__int128_t>(a) * static_cast<__int128_t>(b);
+- const auto cd = static_cast<__int128_t>(c) * static_cast<__int128_t>(d);
+- return ab == cd;
+-#else
++// -- GODOT start --
++// #if (defined(__clang__) || defined(__GNUC__)) && UINTPTR_MAX >= UINT64_MAX
++// const auto ab = static_cast<__int128_t>(a) * static_cast<__int128_t>(b);
++// const auto cd = static_cast<__int128_t>(c) * static_cast<__int128_t>(d);
++// return ab == cd;
++// #else
++// -- GODOT end --
+ // nb: unsigned values needed for calculating overflow carry
+ const auto abs_a = static_cast<uint64_t>(std::abs(a));
+ const auto abs_b = static_cast<uint64_t>(std::abs(b));
+@@ -714,7 +716,9 @@ namespace Clipper2Lib
+ const auto sign_cd = TriSign(c) * TriSign(d);
+
+ return abs_ab == abs_cd && sign_ab == sign_cd;
+-#endif
++// -- GODOT start --
++// #endif
++// -- GODOT end --
+ }
+
+ template <typename T>
diff --git a/thirdparty/clipper2/src/clipper.engine.cpp b/thirdparty/clipper2/src/clipper.engine.cpp
index 9358b74b70..8f120267c3 100644
--- a/thirdparty/clipper2/src/clipper.engine.cpp
+++ b/thirdparty/clipper2/src/clipper.engine.cpp
@@ -1,8 +1,8 @@
/*******************************************************************************
* Author : Angus Johnson *
-* Date : 22 November 2023 *
+* Date : 27 April 2024 *
* Website : http://www.angusj.com *
-* Copyright : Angus Johnson 2010-2023 *
+* Copyright : Angus Johnson 2010-2024 *
* Purpose : This is the main polygon clipping module *
* License : http://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************/
@@ -31,11 +31,11 @@ namespace Clipper2Lib {
static const Rect64 invalid_rect = Rect64(false);
- // Every closed path (or polygon) is made up of a series of vertices forming
- // edges that alternate between going up (relative to the Y-axis) and going
- // down. Edges consecutively going up or consecutively going down are called
- // 'bounds' (ie sides if they're simple polygons). 'Local Minima' refer to
- // vertices where descending bounds become ascending ones.
+ // Every closed path (ie polygon) is made up of a series of vertices forming edge
+ // 'bounds' that alternate between ascending bounds (containing edges going up
+ // relative to the Y-axis) and descending bounds. 'Local Minima' refers to
+ // vertices where ascending and descending bounds join at the bottom, and
+ // 'Local Maxima' are where ascending and descending bounds join at the top.
struct Scanline {
int64_t y = 0;
@@ -63,6 +63,7 @@ namespace Clipper2Lib {
}
};
+
inline bool IsOdd(int val)
{
return (val & 1) ? true : false;
@@ -188,7 +189,7 @@ namespace Clipper2Lib {
}
//PrevPrevVertex: useful to get the (inverted Y-axis) top of the
- //alternate edge (ie left or right bound) during edge insertion.
+ //alternate edge (ie left or right bound) during edge insertion.
inline Vertex* PrevPrevVertex(const Active& ae)
{
if (ae.wind_dx > 0)
@@ -233,15 +234,15 @@ namespace Clipper2Lib {
Vertex* result = e.vertex_top;
if (e.wind_dx > 0)
while ((result->next->pt.y == result->pt.y) &&
- ((result->flags & (VertexFlags::OpenEnd |
+ ((result->flags & (VertexFlags::OpenEnd |
VertexFlags::LocalMax)) == VertexFlags::None))
result = result->next;
else
while (result->prev->pt.y == result->pt.y &&
- ((result->flags & (VertexFlags::OpenEnd |
+ ((result->flags & (VertexFlags::OpenEnd |
VertexFlags::LocalMax)) == VertexFlags::None))
result = result->prev;
- if (!IsMaxima(*result)) result = nullptr; // not a maxima
+ if (!IsMaxima(*result)) result = nullptr; // not a maxima
return result;
}
@@ -252,7 +253,7 @@ namespace Clipper2Lib {
while (result->next->pt.y == result->pt.y) result = result->next;
else
while (result->prev->pt.y == result->pt.y) result = result->prev;
- if (!IsMaxima(*result)) result = nullptr; // not a maxima
+ if (!IsMaxima(*result)) result = nullptr; // not a maxima
return result;
}
@@ -613,13 +614,13 @@ namespace Clipper2Lib {
list.push_back(std::make_unique <LocalMinima>(&vert, polytype, is_open));
}
- void AddPaths_(const Paths64& paths, PathType polytype, bool is_open,
+ void AddPaths_(const Paths64& paths, PathType polytype, bool is_open,
std::vector<Vertex*>& vertexLists, LocalMinimaList& locMinList)
{
const auto total_vertex_count =
- std::accumulate(paths.begin(), paths.end(), 0,
+ std::accumulate(paths.begin(), paths.end(), size_t(0),
[](const auto& a, const Path64& path)
- {return a + static_cast<unsigned>(path.size()); });
+ {return a + path.size(); });
if (total_vertex_count == 0) return;
Vertex* vertices = new Vertex[total_vertex_count], * v = vertices;
@@ -810,7 +811,7 @@ namespace Clipper2Lib {
void ClipperBase::SetZ(const Active& e1, const Active& e2, Point64& ip)
{
if (!zCallback_) return;
- // prioritize subject over clip vertices by passing
+ // prioritize subject over clip vertices by passing
// subject vertices before clip vertices in the callback
if (GetPolyType(e1) == PathType::Subject)
{
@@ -845,11 +846,11 @@ namespace Clipper2Lib {
if (is_open) has_open_paths_ = true;
minima_list_sorted_ = false;
AddPaths_(paths, polytype, is_open, vertex_lists_, minima_list_);
- }
+ }
- void ClipperBase::AddReuseableData(const ReuseableDataContainer64& reuseable_data)
+ void ClipperBase::AddReuseableData(const ReuseableDataContainer64& reuseable_data)
{
- // nb: reuseable_data will continue to own the vertices
+ // nb: reuseable_data will continue to own the vertices
// and remains responsible for their clean up.
succeeded_ = false;
minima_list_sorted_ = false;
@@ -1117,7 +1118,6 @@ namespace Clipper2Lib {
}
}
-
bool IsValidAelOrder(const Active& resident, const Active& newcomer)
{
if (newcomer.curr_x != resident.curr_x)
@@ -1149,8 +1149,8 @@ namespace Clipper2Lib {
//resident must also have just been inserted
else if (resident.is_left_bound != newcomerIsLeft)
return newcomerIsLeft;
- else if (CrossProduct(PrevPrevVertex(resident)->pt,
- resident.bot, resident.top) == 0) return true;
+ else if (IsCollinear(PrevPrevVertex(resident)->pt,
+ resident.bot, resident.top)) return true;
else
//compare turning direction of the alternate bound
return (CrossProduct(PrevPrevVertex(resident)->pt,
@@ -1385,7 +1385,7 @@ namespace Clipper2Lib {
{
if (IsJoined(e1)) Split(e1, pt);
if (IsJoined(e2)) Split(e2, pt);
-
+
if (IsFront(e1) == IsFront(e2))
{
if (IsOpenEnd(e1))
@@ -1409,7 +1409,7 @@ namespace Clipper2Lib {
{
Active* e = GetPrevHotEdge(e1);
if (!e)
- outrec.owner = nullptr;
+ outrec.owner = nullptr;
else
SetOwner(&outrec, e->outrec);
// nb: outRec.owner here is likely NOT the real
@@ -1476,7 +1476,7 @@ namespace Clipper2Lib {
e2.outrec->pts = e1.outrec->pts;
e1.outrec->pts = nullptr;
}
- else
+ else
SetOwner(e2.outrec, e1.outrec);
//and e1 and e2 are maxima and are about to be dropped from the Actives list.
@@ -1526,7 +1526,6 @@ namespace Clipper2Lib {
return new_op;
}
-
void ClipperBase::CleanCollinear(OutRec* outrec)
{
outrec = GetRealOutRec(outrec);
@@ -1541,7 +1540,7 @@ namespace Clipper2Lib {
for (; ; )
{
//NB if preserveCollinear == true, then only remove 180 deg. spikes
- if ((CrossProduct(op2->prev->pt, op2->pt, op2->next->pt) == 0) &&
+ if (IsCollinear(op2->prev->pt, op2->pt, op2->next->pt) &&
(op2->pt == op2->prev->pt ||
op2->pt == op2->next->pt || !preserve_collinear_ ||
DotProduct(op2->prev->pt, op2->pt, op2->next->pt) < 0))
@@ -1566,14 +1565,14 @@ namespace Clipper2Lib {
void ClipperBase::DoSplitOp(OutRec* outrec, OutPt* splitOp)
{
- // splitOp.prev -> splitOp &&
+ // splitOp.prev -> splitOp &&
// splitOp.next -> splitOp.next.next are intersecting
OutPt* prevOp = splitOp->prev;
OutPt* nextNextOp = splitOp->next->next;
outrec->pts = prevOp;
Point64 ip;
- GetIntersectPoint(prevOp->pt, splitOp->pt,
+ GetSegmentIntersectPt(prevOp->pt, splitOp->pt,
splitOp->next->pt, nextNextOp->pt, ip);
#ifdef USINGZ
@@ -1617,7 +1616,7 @@ namespace Clipper2Lib {
{
OutRec* newOr = NewOutRec();
newOr->owner = outrec->owner;
-
+
splitOp->outrec = newOr;
splitOp->next->outrec = newOr;
OutPt* newOp = new OutPt(ip, newOr);
@@ -1772,12 +1771,12 @@ namespace Clipper2Lib {
}
- OutPt* ClipperBase::IntersectEdges(Active& e1, Active& e2, const Point64& pt)
+ void ClipperBase::IntersectEdges(Active& e1, Active& e2, const Point64& pt)
{
//MANAGE OPEN PATH INTERSECTIONS SEPARATELY ...
if (has_open_paths_ && (IsOpen(e1) || IsOpen(e2)))
{
- if (IsOpen(e1) && IsOpen(e2)) return nullptr;
+ if (IsOpen(e1) && IsOpen(e2)) return;
Active* edge_o, * edge_c;
if (IsOpen(e1))
{
@@ -1791,29 +1790,40 @@ namespace Clipper2Lib {
}
if (IsJoined(*edge_c)) Split(*edge_c, pt); // needed for safety
- if (abs(edge_c->wind_cnt) != 1) return nullptr;
+ if (abs(edge_c->wind_cnt) != 1) return;
switch (cliptype_)
{
case ClipType::Union:
- if (!IsHotEdge(*edge_c)) return nullptr;
+ if (!IsHotEdge(*edge_c)) return;
break;
default:
if (edge_c->local_min->polytype == PathType::Subject)
- return nullptr;
+ return;
}
switch (fillrule_)
{
- case FillRule::Positive: if (edge_c->wind_cnt != 1) return nullptr; break;
- case FillRule::Negative: if (edge_c->wind_cnt != -1) return nullptr; break;
- default: if (std::abs(edge_c->wind_cnt) != 1) return nullptr; break;
+ case FillRule::Positive:
+ if (edge_c->wind_cnt != 1) return;
+ break;
+ case FillRule::Negative:
+ if (edge_c->wind_cnt != -1) return;
+ break;
+ default:
+ if (std::abs(edge_c->wind_cnt) != 1) return;
}
+#ifdef USINGZ
OutPt* resultOp;
+#endif
//toggle contribution ...
if (IsHotEdge(*edge_o))
{
+#ifdef USINGZ
resultOp = AddOutPt(*edge_o, pt);
+#else
+ AddOutPt(*edge_o, pt);
+#endif
if (IsFront(*edge_o)) edge_o->outrec->front_edge = nullptr;
else edge_o->outrec->back_edge = nullptr;
edge_o->outrec = nullptr;
@@ -1833,18 +1843,26 @@ namespace Clipper2Lib {
SetSides(*e3->outrec, *edge_o, *e3);
else
SetSides(*e3->outrec, *e3, *edge_o);
- return e3->outrec->pts;
+ return;
}
else
+#ifdef USINGZ
resultOp = StartOpenPath(*edge_o, pt);
+#else
+ StartOpenPath(*edge_o, pt);
+#endif
}
else
+#ifdef USINGZ
resultOp = StartOpenPath(*edge_o, pt);
+#else
+ StartOpenPath(*edge_o, pt);
+#endif
#ifdef USINGZ
if (zCallback_) SetZ(*edge_o, *edge_c, resultOp->pt);
#endif
- return resultOp;
+ return;
} // end of an open path intersection
//MANAGING CLOSED PATHS FROM HERE ON
@@ -1913,22 +1931,25 @@ namespace Clipper2Lib {
const bool e1_windcnt_in_01 = old_e1_windcnt == 0 || old_e1_windcnt == 1;
const bool e2_windcnt_in_01 = old_e2_windcnt == 0 || old_e2_windcnt == 1;
- if ((!IsHotEdge(e1) && !e1_windcnt_in_01) || (!IsHotEdge(e2) && !e2_windcnt_in_01))
- {
- return nullptr;
- }
+ if ((!IsHotEdge(e1) && !e1_windcnt_in_01) ||
+ (!IsHotEdge(e2) && !e2_windcnt_in_01))
+ return;
//NOW PROCESS THE INTERSECTION ...
+#ifdef USINGZ
OutPt* resultOp = nullptr;
+#endif
//if both edges are 'hot' ...
if (IsHotEdge(e1) && IsHotEdge(e2))
{
if ((old_e1_windcnt != 0 && old_e1_windcnt != 1) || (old_e2_windcnt != 0 && old_e2_windcnt != 1) ||
(e1.local_min->polytype != e2.local_min->polytype && cliptype_ != ClipType::Xor))
{
- resultOp = AddLocalMaxPoly(e1, e2, pt);
#ifdef USINGZ
+ resultOp = AddLocalMaxPoly(e1, e2, pt);
if (zCallback_ && resultOp) SetZ(e1, e2, resultOp->pt);
+#else
+ AddLocalMaxPoly(e1, e2, pt);
#endif
}
else if (IsFront(e1) || (e1.outrec == e2.outrec))
@@ -1937,19 +1958,20 @@ namespace Clipper2Lib {
//it's sensible to split polygons that ony touch at
//a common vertex (not at common edges).
- resultOp = AddLocalMaxPoly(e1, e2, pt);
#ifdef USINGZ
+ resultOp = AddLocalMaxPoly(e1, e2, pt);
OutPt* op2 = AddLocalMinPoly(e1, e2, pt);
if (zCallback_ && resultOp) SetZ(e1, e2, resultOp->pt);
if (zCallback_) SetZ(e1, e2, op2->pt);
#else
+ AddLocalMaxPoly(e1, e2, pt);
AddLocalMinPoly(e1, e2, pt);
#endif
}
else
{
- resultOp = AddOutPt(e1, pt);
#ifdef USINGZ
+ resultOp = AddOutPt(e1, pt);
OutPt* op2 = AddOutPt(e2, pt);
if (zCallback_)
{
@@ -1957,6 +1979,7 @@ namespace Clipper2Lib {
SetZ(e1, e2, op2->pt);
}
#else
+ AddOutPt(e1, pt);
AddOutPt(e2, pt);
#endif
SwapOutrecs(e1, e2);
@@ -1964,17 +1987,21 @@ namespace Clipper2Lib {
}
else if (IsHotEdge(e1))
{
- resultOp = AddOutPt(e1, pt);
#ifdef USINGZ
+ resultOp = AddOutPt(e1, pt);
if (zCallback_) SetZ(e1, e2, resultOp->pt);
+#else
+ AddOutPt(e1, pt);
#endif
SwapOutrecs(e1, e2);
}
else if (IsHotEdge(e2))
{
- resultOp = AddOutPt(e2, pt);
#ifdef USINGZ
+ resultOp = AddOutPt(e2, pt);
if (zCallback_) SetZ(e1, e2, resultOp->pt);
+#else
+ AddOutPt(e2, pt);
#endif
SwapOutrecs(e1, e2);
}
@@ -2004,33 +2031,53 @@ namespace Clipper2Lib {
if (!IsSamePolyType(e1, e2))
{
- resultOp = AddLocalMinPoly(e1, e2, pt, false);
#ifdef USINGZ
+ resultOp = AddLocalMinPoly(e1, e2, pt, false);
if (zCallback_) SetZ(e1, e2, resultOp->pt);
+#else
+ AddLocalMinPoly(e1, e2, pt, false);
#endif
}
else if (old_e1_windcnt == 1 && old_e2_windcnt == 1)
{
+#ifdef USINGZ
resultOp = nullptr;
+#endif
switch (cliptype_)
{
case ClipType::Union:
if (e1Wc2 <= 0 && e2Wc2 <= 0)
+#ifdef USINGZ
resultOp = AddLocalMinPoly(e1, e2, pt, false);
+#else
+ AddLocalMinPoly(e1, e2, pt, false);
+#endif
break;
case ClipType::Difference:
if (((GetPolyType(e1) == PathType::Clip) && (e1Wc2 > 0) && (e2Wc2 > 0)) ||
((GetPolyType(e1) == PathType::Subject) && (e1Wc2 <= 0) && (e2Wc2 <= 0)))
{
+#ifdef USINGZ
resultOp = AddLocalMinPoly(e1, e2, pt, false);
+#else
+ AddLocalMinPoly(e1, e2, pt, false);
+#endif
}
break;
case ClipType::Xor:
+#ifdef USINGZ
resultOp = AddLocalMinPoly(e1, e2, pt, false);
+#else
+ AddLocalMinPoly(e1, e2, pt, false);
+#endif
break;
default:
if (e1Wc2 > 0 && e2Wc2 > 0)
+#ifdef USINGZ
resultOp = AddLocalMinPoly(e1, e2, pt, false);
+#else
+ AddLocalMinPoly(e1, e2, pt, false);
+#endif
break;
}
#ifdef USINGZ
@@ -2038,7 +2085,6 @@ namespace Clipper2Lib {
#endif
}
}
- return resultOp;
}
inline void ClipperBase::DeleteFromAEL(Active& e)
@@ -2065,7 +2111,7 @@ namespace Clipper2Lib {
e->next_in_sel = e->next_in_ael;
e->jump = e->next_in_sel;
if (e->join_with == JoinWith::Left)
- e->curr_x = e->prev_in_ael->curr_x; // also avoids complications
+ e->curr_x = e->prev_in_ael->curr_x; // also avoids complications
else
e->curr_x = TopX(*e, top_y);
e = e->next_in_ael;
@@ -2138,7 +2184,7 @@ namespace Clipper2Lib {
if (outrecHasEdges)
{
OutPt* opA = outrec->pts, * opZ = opA->next;
- while (opP != opZ && opP->prev->pt.y == curr_y)
+ while (opP != opZ && opP->prev->pt.y == curr_y)
opP = opP->prev;
while (opN != opA && opN->next->pt.y == curr_y)
opN = opN->next;
@@ -2150,7 +2196,7 @@ namespace Clipper2Lib {
while (opN->next != opP && opN->next->pt.y == curr_y)
opN = opN->next;
}
- bool result =
+ bool result =
SetHorzSegHeadingForward(hs, opP, opN) &&
!hs.left_op->horz;
@@ -2160,13 +2206,14 @@ namespace Clipper2Lib {
hs.right_op = nullptr; // (for sorting)
return result;
}
-
+
void ClipperBase::ConvertHorzSegsToJoins()
{
- auto j = std::count_if(horz_seg_list_.begin(),
+ auto j = std::count_if(horz_seg_list_.begin(),
horz_seg_list_.end(),
[](HorzSegment& hs) { return UpdateHorzSegment(hs); });
if (j < 2) return;
+
std::stable_sort(horz_seg_list_.begin(), horz_seg_list_.end(), HorzSegSorter());
HorzSegmentList::iterator hs1 = horz_seg_list_.begin(), hs2;
@@ -2207,8 +2254,8 @@ namespace Clipper2Lib {
DuplicateOp(hs1->left_op, false));
horz_join_list_.push_back(join);
}
- }
- }
+ }
+ }
}
void MoveSplits(OutRec* fromOr, OutRec* toOr)
@@ -2301,7 +2348,7 @@ namespace Clipper2Lib {
void ClipperBase::AddNewIntersectNode(Active& e1, Active& e2, int64_t top_y)
{
Point64 ip;
- if (!GetIntersectPoint(e1.bot, e1.top, e2.bot, e2.top, ip))
+ if (!GetSegmentIntersectPt(e1.bot, e1.top, e2.bot, e2.top, ip))
ip = Point64(e1.curr_x, top_y); //parallel edges
//rounding errors can occasionally place the calculated intersection
@@ -2321,7 +2368,7 @@ namespace Clipper2Lib {
ip = GetClosestPointOnSegment(ip, e1.bot, e1.top);
else if (abs_dx2 > 100)
ip = GetClosestPointOnSegment(ip, e2.bot, e2.top);
- else
+ else
{
if (ip.y < top_y) ip.y = top_y;
else ip.y = bot_y_;
@@ -2453,7 +2500,7 @@ namespace Clipper2Lib {
horz_seg_list_.push_back(HorzSegment(op));
}
- bool ClipperBase::ResetHorzDirection(const Active& horz,
+ bool ClipperBase::ResetHorzDirection(const Active& horz,
const Vertex* max_vertex, int64_t& horz_left, int64_t& horz_right)
{
if (horz.bot.x == horz.top.x)
@@ -2536,8 +2583,8 @@ namespace Clipper2Lib {
if (IsHotEdge(horz) && IsJoined(*e))
Split(*e, e->top);
- //if (IsHotEdge(horz) != IsHotEdge(*e))
- // DoError(undefined_error_i);
+ //if (IsHotEdge(horz) != IsHotEdge(*e))
+ // DoError(undefined_error_i);
if (IsHotEdge(horz))
{
@@ -2641,7 +2688,7 @@ namespace Clipper2Lib {
ResetHorzDirection(horz, vertex_max, horz_left, horz_right);
}
- if (IsHotEdge(horz))
+ if (IsHotEdge(horz))
{
OutPt* op = AddOutPt(horz, horz.top);
AddTrialHorzJoin(op);
@@ -2754,21 +2801,23 @@ namespace Clipper2Lib {
}
}
- void ClipperBase::CheckJoinLeft(Active& e,
+ void ClipperBase::CheckJoinLeft(Active& e,
const Point64& pt, bool check_curr_x)
{
Active* prev = e.prev_in_ael;
- if (IsOpen(e) || !IsHotEdge(e) || !prev ||
- IsOpen(*prev) || !IsHotEdge(*prev)) return;
+ if (!prev ||
+ !IsHotEdge(e) || !IsHotEdge(*prev) ||
+ IsHorizontal(e) || IsHorizontal(*prev) ||
+ IsOpen(e) || IsOpen(*prev) ) return;
if ((pt.y < e.top.y + 2 || pt.y < prev->top.y + 2) &&
- ((e.bot.y > pt.y) || (prev->bot.y > pt.y))) return; // avoid trivial joins
+ ((e.bot.y > pt.y) || (prev->bot.y > pt.y))) return; // avoid trivial joins
if (check_curr_x)
{
- if (DistanceFromLineSqrd(pt, prev->bot, prev->top) > 0.25) return;
+ if (PerpendicDistFromLineSqrd(pt, prev->bot, prev->top) > 0.25) return;
}
else if (e.curr_x != prev->curr_x) return;
- if (CrossProduct(e.top, pt, prev->top)) return;
+ if (!IsCollinear(e.top, pt, prev->top)) return;
if (e.outrec->idx == prev->outrec->idx)
AddLocalMaxPoly(*prev, e, pt);
@@ -2780,22 +2829,24 @@ namespace Clipper2Lib {
e.join_with = JoinWith::Left;
}
- void ClipperBase::CheckJoinRight(Active& e,
+ void ClipperBase::CheckJoinRight(Active& e,
const Point64& pt, bool check_curr_x)
{
Active* next = e.next_in_ael;
- if (IsOpen(e) || !IsHotEdge(e) ||
- !next || IsOpen(*next) || !IsHotEdge(*next)) return;
+ if (!next ||
+ !IsHotEdge(e) || !IsHotEdge(*next) ||
+ IsHorizontal(e) || IsHorizontal(*next) ||
+ IsOpen(e) || IsOpen(*next)) return;
if ((pt.y < e.top.y +2 || pt.y < next->top.y +2) &&
- ((e.bot.y > pt.y) || (next->bot.y > pt.y))) return; // avoid trivial joins
+ ((e.bot.y > pt.y) || (next->bot.y > pt.y))) return; // avoid trivial joins
if (check_curr_x)
{
- if (DistanceFromLineSqrd(pt, next->bot, next->top) > 0.35) return;
+ if (PerpendicDistFromLineSqrd(pt, next->bot, next->top) > 0.35) return;
}
else if (e.curr_x != next->curr_x) return;
- if (CrossProduct(e.top, pt, next->top)) return;
-
+ if (!IsCollinear(e.top, pt, next->top)) return;
+
if (e.outrec->idx == next->outrec->idx)
AddLocalMaxPoly(e, *next, pt);
else if (e.outrec->idx < next->outrec->idx)
@@ -2863,7 +2914,7 @@ namespace Clipper2Lib {
op2 = op2->next;
}
- if (path.size() == 3 && IsVerySmallTriangle(*op2)) return false;
+ if (!isOpen && path.size() == 3 && IsVerySmallTriangle(*op2)) return false;
else return true;
}
@@ -2872,8 +2923,8 @@ namespace Clipper2Lib {
if (!outrec->pts) return false;
if (!outrec->bounds.IsEmpty()) return true;
CleanCollinear(outrec);
- if (!outrec->pts ||
- !BuildPath64(outrec->pts, reverse_solution_, false, outrec->path)){
+ if (!outrec->pts ||
+ !BuildPath64(outrec->pts, reverse_solution_, false, outrec->path)){
return false;}
outrec->bounds = GetBounds(outrec->path);
return true;
@@ -2887,10 +2938,10 @@ namespace Clipper2Lib {
if(!split || split == outrec || split->recursive_split == outrec) continue;
split->recursive_split = outrec; // prevent infinite loops
- if (split->splits && CheckSplitOwner(outrec, split->splits))
+ if (split->splits && CheckSplitOwner(outrec, split->splits))
return true;
- else if (CheckBounds(split) &&
- IsValidOwner(outrec, split) &&
+ else if (CheckBounds(split) &&
+ IsValidOwner(outrec, split) &&
split->bounds.Contains(outrec->bounds) &&
Path1InsidePath2(outrec->pts, split->pts))
{
@@ -2919,7 +2970,7 @@ namespace Clipper2Lib {
if (outrec->owner)
{
- if (!outrec->owner->polypath)
+ if (!outrec->owner->polypath)
RecursiveCheckOwners(outrec->owner, polypath);
outrec->polypath = outrec->owner->polypath->AddChild(outrec->path);
}
@@ -2968,7 +3019,7 @@ namespace Clipper2Lib {
open_paths.resize(0);
if (has_open_paths_)
open_paths.reserve(outrec_list_.size());
-
+
// outrec_list_.size() is not static here because
// CheckBounds below can indirectly add additional
// OutRec (via FixOutRecPts & CleanCollinear)
@@ -2991,7 +3042,7 @@ namespace Clipper2Lib {
bool BuildPathD(OutPt* op, bool reverse, bool isOpen, PathD& path, double inv_scale)
{
- if (!op || op->next == op || (!isOpen && op->next == op->prev))
+ if (!op || op->next == op || (!isOpen && op->next == op->prev))
return false;
path.resize(0);
@@ -3024,7 +3075,7 @@ namespace Clipper2Lib {
#else
path.push_back(PointD(lastPt.x * inv_scale, lastPt.y * inv_scale));
#endif
-
+
}
if (reverse)
op2 = op2->prev;
diff --git a/thirdparty/clipper2/src/clipper.offset.cpp b/thirdparty/clipper2/src/clipper.offset.cpp
index 0282aa49bb..508a7f0831 100644
--- a/thirdparty/clipper2/src/clipper.offset.cpp
+++ b/thirdparty/clipper2/src/clipper.offset.cpp
@@ -1,8 +1,8 @@
/*******************************************************************************
* Author : Angus Johnson *
-* Date : 28 November 2023 *
+* Date : 17 April 2024 *
* Website : http://www.angusj.com *
-* Copyright : Angus Johnson 2010-2023 *
+* Copyright : Angus Johnson 2010-2024 *
* Purpose : Path Offset (Inflate/Shrink) *
* License : http://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************/
@@ -20,60 +20,19 @@ const double floating_point_tolerance = 1e-12;
// Miscellaneous methods
//------------------------------------------------------------------------------
-inline bool ToggleBoolIf(bool val, bool condition)
+std::optional<size_t> GetLowestClosedPathIdx(const Paths64& paths)
{
- return condition ? !val : val;
-}
-
-void GetMultiBounds(const Paths64& paths, std::vector<Rect64>& recList)
-{
- recList.reserve(paths.size());
- for (const Path64& path : paths)
- {
- if (path.size() < 1)
- {
- recList.push_back(InvalidRect64);
- continue;
- }
- int64_t x = path[0].x, y = path[0].y;
- Rect64 r = Rect64(x, y, x, y);
- for (const Point64& pt : path)
- {
- if (pt.y > r.bottom) r.bottom = pt.y;
- else if (pt.y < r.top) r.top = pt.y;
- if (pt.x > r.right) r.right = pt.x;
- else if (pt.x < r.left) r.left = pt.x;
- }
- recList.push_back(r);
- }
-}
-
-bool ValidateBounds(std::vector<Rect64>& recList, double delta)
-{
- int64_t int_delta = static_cast<int64_t>(delta);
- int64_t big = MAX_COORD - int_delta;
- int64_t small = MIN_COORD + int_delta;
- for (const Rect64& r : recList)
- {
- if (!r.IsValid()) continue; // ignore invalid paths
- else if (r.left < small || r.right > big ||
- r.top < small || r.bottom > big) return false;
- }
- return true;
-}
-
-int GetLowestClosedPathIdx(std::vector<Rect64>& boundsList)
-{
- int i = -1, result = -1;
+ std::optional<size_t> result;
Point64 botPt = Point64(INT64_MAX, INT64_MIN);
- for (const Rect64& r : boundsList)
- {
- ++i;
- if (!r.IsValid()) continue; // ignore invalid paths
- else if (r.bottom > botPt.y || (r.bottom == botPt.y && r.left < botPt.x))
+ for (size_t i = 0; i < paths.size(); ++i)
+ {
+ for (const Point64& pt : paths[i])
{
- botPt = Point64(r.left, r.bottom);
- result = static_cast<int>(i);
+ if ((pt.y < botPt.y) ||
+ ((pt.y == botPt.y) && (pt.x >= botPt.x))) continue;
+ result = i;
+ botPt.x = pt.x;
+ botPt.y = pt.y;
}
}
return result;
@@ -96,14 +55,14 @@ inline bool AlmostZero(double value, double epsilon = 0.001)
return std::fabs(value) < epsilon;
}
-inline double Hypot(double x, double y)
+inline double Hypot(double x, double y)
{
//see https://stackoverflow.com/a/32436148/359538
return std::sqrt(x * x + y * y);
}
inline PointD NormalizeVector(const PointD& vec)
-{
+{
double h = Hypot(vec.x, vec.y);
if (AlmostZero(h)) return PointD(0,0);
double inverseHypot = 1 / h;
@@ -164,30 +123,21 @@ ClipperOffset::Group::Group(const Paths64& _paths, JoinType _join_type, EndType
for (Path64& p: paths_in)
StripDuplicates(p, is_joined);
- // get bounds of each path --> bounds_list
- GetMultiBounds(paths_in, bounds_list);
-
if (end_type == EndType::Polygon)
{
- is_hole_list.reserve(paths_in.size());
- for (const Path64& path : paths_in)
- is_hole_list.push_back(Area(path) < 0);
- lowest_path_idx = GetLowestClosedPathIdx(bounds_list);
+ lowest_path_idx = GetLowestClosedPathIdx(paths_in);
// the lowermost path must be an outer path, so if its orientation is negative,
// then flag the whole group is 'reversed' (will negate delta etc.)
// as this is much more efficient than reversing every path.
- is_reversed = (lowest_path_idx >= 0) && is_hole_list[lowest_path_idx];
- if (is_reversed) is_hole_list.flip();
+ is_reversed = (lowest_path_idx.has_value()) && Area(paths_in[lowest_path_idx.value()]) < 0;
}
else
{
- lowest_path_idx = -1;
+ lowest_path_idx = std::nullopt;
is_reversed = false;
- is_hole_list.resize(paths_in.size());
}
}
-
//------------------------------------------------------------------------------
// ClipperOffset methods
//------------------------------------------------------------------------------
@@ -216,66 +166,29 @@ void ClipperOffset::BuildNormals(const Path64& path)
norms.push_back(GetUnitNormal(*path_stop_iter, *(path.cbegin())));
}
-inline PointD TranslatePoint(const PointD& pt, double dx, double dy)
-{
-#ifdef USINGZ
- return PointD(pt.x + dx, pt.y + dy, pt.z);
-#else
- return PointD(pt.x + dx, pt.y + dy);
-#endif
-}
-
-inline PointD ReflectPoint(const PointD& pt, const PointD& pivot)
-{
-#ifdef USINGZ
- return PointD(pivot.x + (pivot.x - pt.x), pivot.y + (pivot.y - pt.y), pt.z);
-#else
- return PointD(pivot.x + (pivot.x - pt.x), pivot.y + (pivot.y - pt.y));
-#endif
-}
-
-PointD IntersectPoint(const PointD& pt1a, const PointD& pt1b,
- const PointD& pt2a, const PointD& pt2b)
-{
- if (pt1a.x == pt1b.x) //vertical
- {
- if (pt2a.x == pt2b.x) return PointD(0, 0);
-
- double m2 = (pt2b.y - pt2a.y) / (pt2b.x - pt2a.x);
- double b2 = pt2a.y - m2 * pt2a.x;
- return PointD(pt1a.x, m2 * pt1a.x + b2);
- }
- else if (pt2a.x == pt2b.x) //vertical
- {
- double m1 = (pt1b.y - pt1a.y) / (pt1b.x - pt1a.x);
- double b1 = pt1a.y - m1 * pt1a.x;
- return PointD(pt2a.x, m1 * pt2a.x + b1);
- }
- else
- {
- double m1 = (pt1b.y - pt1a.y) / (pt1b.x - pt1a.x);
- double b1 = pt1a.y - m1 * pt1a.x;
- double m2 = (pt2b.y - pt2a.y) / (pt2b.x - pt2a.x);
- double b2 = pt2a.y - m2 * pt2a.x;
- if (m1 == m2) return PointD(0, 0);
- double x = (b2 - b1) / (m1 - m2);
- return PointD(x, m1 * x + b1);
- }
-}
-
void ClipperOffset::DoBevel(const Path64& path, size_t j, size_t k)
{
PointD pt1, pt2;
if (j == k)
{
double abs_delta = std::abs(group_delta_);
+#ifdef USINGZ
+ pt1 = PointD(path[j].x - abs_delta * norms[j].x, path[j].y - abs_delta * norms[j].y, path[j].z);
+ pt2 = PointD(path[j].x + abs_delta * norms[j].x, path[j].y + abs_delta * norms[j].y, path[j].z);
+#else
pt1 = PointD(path[j].x - abs_delta * norms[j].x, path[j].y - abs_delta * norms[j].y);
pt2 = PointD(path[j].x + abs_delta * norms[j].x, path[j].y + abs_delta * norms[j].y);
- }
+#endif
+ }
else
{
+#ifdef USINGZ
+ pt1 = PointD(path[j].x + group_delta_ * norms[k].x, path[j].y + group_delta_ * norms[k].y, path[j].z);
+ pt2 = PointD(path[j].x + group_delta_ * norms[j].x, path[j].y + group_delta_ * norms[j].y, path[j].z);
+#else
pt1 = PointD(path[j].x + group_delta_ * norms[k].x, path[j].y + group_delta_ * norms[k].y);
pt2 = PointD(path[j].x + group_delta_ * norms[j].x, path[j].y + group_delta_ * norms[j].y);
+#endif
}
path_out.push_back(Point64(pt1));
path_out.push_back(Point64(pt2));
@@ -284,7 +197,7 @@ void ClipperOffset::DoBevel(const Path64& path, size_t j, size_t k)
void ClipperOffset::DoSquare(const Path64& path, size_t j, size_t k)
{
PointD vec;
- if (j == k)
+ if (j == k)
vec = PointD(norms[j].y, -norms[j].x);
else
vec = GetAvgUnitVector(
@@ -304,10 +217,8 @@ void ClipperOffset::DoSquare(const Path64& path, size_t j, size_t k)
if (j == k)
{
PointD pt4 = PointD(pt3.x + vec.x * group_delta_, pt3.y + vec.y * group_delta_);
- PointD pt = IntersectPoint(pt1, pt2, pt3, pt4);
-#ifdef USINGZ
- pt.z = ptQ.z;
-#endif
+ PointD pt = ptQ;
+ GetSegmentIntersectPt(pt1, pt2, pt3, pt4, pt);
//get the second intersect point through reflecion
path_out.push_back(Point64(ReflectPoint(pt, ptQ)));
path_out.push_back(Point64(pt));
@@ -315,10 +226,8 @@ void ClipperOffset::DoSquare(const Path64& path, size_t j, size_t k)
else
{
PointD pt4 = GetPerpendicD(path[j], norms[k], group_delta_);
- PointD pt = IntersectPoint(pt1, pt2, pt3, pt4);
-#ifdef USINGZ
- pt.z = ptQ.z;
-#endif
+ PointD pt = ptQ;
+ GetSegmentIntersectPt(pt1, pt2, pt3, pt4, pt);
path_out.push_back(Point64(pt));
//get the second intersect point through reflecion
path_out.push_back(Point64(ReflectPoint(pt, ptQ)));
@@ -343,7 +252,7 @@ void ClipperOffset::DoMiter(const Path64& path, size_t j, size_t k, double cos_a
void ClipperOffset::DoRound(const Path64& path, size_t j, size_t k, double angle)
{
if (deltaCallback64_) {
- // when deltaCallback64_ is assigned, group_delta_ won't be constant,
+ // when deltaCallback64_ is assigned, group_delta_ won't be constant,
// so we'll need to do the following calculations for *every* vertex.
double abs_delta = std::fabs(group_delta_);
double arcTol = (arc_tolerance_ > floating_point_tolerance ?
@@ -387,7 +296,7 @@ void ClipperOffset::OffsetPoint(Group& group, const Path64& path, size_t j, size
// sin(A) < 0: right turning
// cos(A) < 0: change in angle is more than 90 degree
- if (path[j] == path[k]) { k = j; return; }
+ if (path[j] == path[k]) return;
double sin_a = CrossProduct(norms[j], norms[k]);
double cos_a = DotProduct(norms[j], norms[k]);
@@ -404,18 +313,29 @@ void ClipperOffset::OffsetPoint(Group& group, const Path64& path, size_t j, size
return;
}
- if (cos_a > -0.99 && (sin_a * group_delta_ < 0)) // test for concavity first (#593)
+ if (cos_a > -0.999 && (sin_a * group_delta_ < 0)) // test for concavity first (#593)
{
- // is concave
+ // is concave (so insert 3 points that will create a negative region)
+#ifdef USINGZ
+ path_out.push_back(Point64(GetPerpendic(path[j], norms[k], group_delta_), path[j].z));
+#else
path_out.push_back(GetPerpendic(path[j], norms[k], group_delta_));
- // this extra point is the only (simple) way to ensure that
- // path reversals are fully cleaned with the trailing clipper
- path_out.push_back(path[j]); // (#405)
+#endif
+
+ // this extra point is the only simple way to ensure that path reversals
+ // (ie over-shrunk paths) are fully cleaned out with the trailing union op.
+ // However it's probably safe to skip this whenever an angle is almost flat.
+ if (cos_a < 0.99) path_out.push_back(path[j]); // (#405)
+
+#ifdef USINGZ
+ path_out.push_back(Point64(GetPerpendic(path[j], norms[j], group_delta_), path[j].z));
+#else
path_out.push_back(GetPerpendic(path[j], norms[j], group_delta_));
+#endif
}
- else if (cos_a > 0.999 && join_type_ != JoinType::Round)
+ else if (cos_a > 0.999 && join_type_ != JoinType::Round)
{
- // almost straight - less than 2.5 degree (#424, #482, #526 & #724)
+ // almost straight - less than 2.5 degree (#424, #482, #526 & #724)
DoMiter(path, j, k, cos_a);
}
else if (join_type_ == JoinType::Miter)
@@ -435,9 +355,9 @@ void ClipperOffset::OffsetPoint(Group& group, const Path64& path, size_t j, size
void ClipperOffset::OffsetPolygon(Group& group, const Path64& path)
{
path_out.clear();
- for (Path64::size_type j = 0, k = path.size() -1; j < path.size(); k = j, ++j)
- OffsetPoint(group, path, j, k);
- solution.push_back(path_out);
+ for (Path64::size_type j = 0, k = path.size() - 1; j < path.size(); k = j, ++j)
+ OffsetPoint(group, path, j, k);
+ solution->push_back(path_out);
}
void ClipperOffset::OffsetOpenJoined(Group& group, const Path64& path)
@@ -445,8 +365,8 @@ void ClipperOffset::OffsetOpenJoined(Group& group, const Path64& path)
OffsetPolygon(group, path);
Path64 reverse_path(path);
std::reverse(reverse_path.begin(), reverse_path.end());
-
- //rebuild normals // BuildNormals(path);
+
+ //rebuild normals
std::reverse(norms.begin(), norms.end());
norms.push_back(norms[0]);
norms.erase(norms.begin());
@@ -459,7 +379,7 @@ void ClipperOffset::OffsetOpenPath(Group& group, const Path64& path)
{
// do the line start cap
if (deltaCallback64_) group_delta_ = deltaCallback64_(path, norms, 0, 0);
-
+
if (std::fabs(group_delta_) <= floating_point_tolerance)
path_out.push_back(path[0]);
else
@@ -477,13 +397,13 @@ void ClipperOffset::OffsetOpenPath(Group& group, const Path64& path)
break;
}
}
-
+
size_t highI = path.size() - 1;
// offset the left side going forward
for (Path64::size_type j = 1, k = 0; j < highI; k = j, ++j)
OffsetPoint(group, path, j, k);
- // reverse normals
+ // reverse normals
for (size_t i = highI; i > 0; --i)
norms[i] = PointD(-norms[i - 1].x, -norms[i - 1].y);
norms[0] = norms[highI];
@@ -510,41 +430,34 @@ void ClipperOffset::OffsetOpenPath(Group& group, const Path64& path)
}
}
- for (size_t j = highI, k = 0; j > 0; k = j, --j)
+ for (size_t j = highI -1, k = highI; j > 0; k = j, --j)
OffsetPoint(group, path, j, k);
- solution.push_back(path_out);
+ solution->push_back(path_out);
}
void ClipperOffset::DoGroupOffset(Group& group)
{
if (group.end_type == EndType::Polygon)
{
- // a straight path (2 points) can now also be 'polygon' offset
+ // a straight path (2 points) can now also be 'polygon' offset
// where the ends will be treated as (180 deg.) joins
- if (group.lowest_path_idx < 0) delta_ = std::abs(delta_);
+ if (!group.lowest_path_idx.has_value()) delta_ = std::abs(delta_);
group_delta_ = (group.is_reversed) ? -delta_ : delta_;
}
else
group_delta_ = std::abs(delta_);// *0.5;
double abs_delta = std::fabs(group_delta_);
- if (!ValidateBounds(group.bounds_list, abs_delta))
- {
- DoError(range_error_i);
- error_code_ |= range_error_i;
- return;
- }
-
join_type_ = group.join_type;
end_type_ = group.end_type;
if (group.join_type == JoinType::Round || group.end_type == EndType::Round)
{
- // calculate a sensible number of steps (for 360 deg for the given offset)
- // arcTol - when arc_tolerance_ is undefined (0), the amount of
- // curve imprecision that's allowed is based on the size of the
- // offset (delta). Obviously very large offsets will almost always
- // require much less precision. See also offset_triginometry2.svg
+ // calculate the number of steps required to approximate a circle
+ // (see http://www.angusj.com/clipper2/Docs/Trigonometry.htm)
+ // arcTol - when arc_tolerance_ is undefined (0) then curve imprecision
+ // will be relative to the size of the offset (delta). Obviously very
+ //large offsets will almost always require much less precision.
double arcTol = (arc_tolerance_ > floating_point_tolerance ?
std::min(abs_delta, arc_tolerance_) :
std::log10(2 + abs_delta) * default_arc_tolerance);
@@ -556,24 +469,29 @@ void ClipperOffset::DoGroupOffset(Group& group)
steps_per_rad_ = steps_per_360 / (2 * PI);
}
- std::vector<Rect64>::const_iterator path_rect_it = group.bounds_list.cbegin();
- std::vector<bool>::const_iterator is_hole_it = group.is_hole_list.cbegin();
+ //double min_area = PI * Sqr(group_delta_);
Paths64::const_iterator path_in_it = group.paths_in.cbegin();
- for ( ; path_in_it != group.paths_in.cend(); ++path_in_it, ++path_rect_it, ++is_hole_it)
+ for ( ; path_in_it != group.paths_in.cend(); ++path_in_it)
{
- if (!path_rect_it->IsValid()) continue;
Path64::size_type pathLen = path_in_it->size();
path_out.clear();
if (pathLen == 1) // single point
{
+ if (deltaCallback64_)
+ {
+ group_delta_ = deltaCallback64_(*path_in_it, norms, 0, 0);
+ if (group.is_reversed) group_delta_ = -group_delta_;
+ abs_delta = std::fabs(group_delta_);
+ }
+
if (group_delta_ < 1) continue;
const Point64& pt = (*path_in_it)[0];
//single vertex so build a circle or square ...
if (group.join_type == JoinType::Round)
{
double radius = abs_delta;
- int steps = static_cast<int>(std::ceil(steps_per_rad_ * 2 * PI)); //#617
+ size_t steps = steps_per_rad_ > 0 ? static_cast<size_t>(std::ceil(steps_per_rad_ * 2 * PI)) : 0; //#617
path_out = Ellipse(pt, radius, radius, steps);
#ifdef USINGZ
for (auto& p : path_out) p.z = pt.z;
@@ -588,19 +506,14 @@ void ClipperOffset::DoGroupOffset(Group& group)
for (auto& p : path_out) p.z = pt.z;
#endif
}
- solution.push_back(path_out);
- continue;
- } // end of offsetting a single point
- // when shrinking outer paths, make sure they can shrink this far (#593)
- // also when shrinking holes, make sure they too can shrink this far (#715)
- if ((group_delta_ > 0) == ToggleBoolIf(*is_hole_it, group.is_reversed) &&
- (std::min(path_rect_it->Width(), path_rect_it->Height()) <= -group_delta_ * 2) )
- continue;
+ solution->push_back(path_out);
+ continue;
+ } // end of offsetting a single point
if ((pathLen == 2) && (group.end_type == EndType::Joined))
- end_type_ = (group.join_type == JoinType::Round) ?
- EndType::Round :
+ end_type_ = (group.join_type == JoinType::Round) ?
+ EndType::Round :
EndType::Square;
BuildNormals(*path_in_it);
@@ -610,6 +523,16 @@ void ClipperOffset::DoGroupOffset(Group& group)
}
}
+#ifdef USINGZ
+void ClipperOffset::ZCB(const Point64& bot1, const Point64& top1,
+ const Point64& bot2, const Point64& top2, Point64& ip)
+{
+ if (bot1.z && ((bot1.z == bot2.z) || (bot1.z == top2.z))) ip.z = bot1.z;
+ else if (bot2.z && (bot2.z == top1.z)) ip.z = bot2.z;
+ else if (top1.z && (top1.z == top2.z)) ip.z = top1.z;
+ else if (zCallback64_) zCallback64_(bot1, top1, bot2, top2, ip);
+}
+#endif
size_t ClipperOffset::CalcSolutionCapacity()
{
@@ -635,40 +558,35 @@ bool ClipperOffset::CheckReverseOrientation()
void ClipperOffset::ExecuteInternal(double delta)
{
error_code_ = 0;
- solution.clear();
if (groups_.size() == 0) return;
- solution.reserve(CalcSolutionCapacity());
+ solution->reserve(CalcSolutionCapacity());
- if (std::abs(delta) < 0.5) // ie: offset is insignificant
+ if (std::abs(delta) < 0.5) // ie: offset is insignificant
{
Paths64::size_type sol_size = 0;
for (const Group& group : groups_) sol_size += group.paths_in.size();
- solution.reserve(sol_size);
+ solution->reserve(sol_size);
for (const Group& group : groups_)
- copy(group.paths_in.begin(), group.paths_in.end(), back_inserter(solution));
- return;
+ copy(group.paths_in.begin(), group.paths_in.end(), back_inserter(*solution));
}
+ else
+ {
- temp_lim_ = (miter_limit_ <= 1) ?
- 2.0 :
- 2.0 / (miter_limit_ * miter_limit_);
+ temp_lim_ = (miter_limit_ <= 1) ?
+ 2.0 :
+ 2.0 / (miter_limit_ * miter_limit_);
- delta_ = delta;
- std::vector<Group>::iterator git;
- for (git = groups_.begin(); git != groups_.end(); ++git)
- {
- DoGroupOffset(*git);
- if (!error_code_) continue; // all OK
- solution.clear();
+ delta_ = delta;
+ std::vector<Group>::iterator git;
+ for (git = groups_.begin(); git != groups_.end(); ++git)
+ {
+ DoGroupOffset(*git);
+ if (!error_code_) continue; // all OK
+ solution->clear();
+ }
}
-}
-void ClipperOffset::Execute(double delta, Paths64& paths)
-{
- paths.clear();
-
- ExecuteInternal(delta);
- if (!solution.size()) return;
+ if (!solution->size()) return;
bool paths_reversed = CheckReverseOrientation();
//clean up self-intersections ...
@@ -677,41 +595,45 @@ void ClipperOffset::Execute(double delta, Paths64& paths)
//the solution should retain the orientation of the input
c.ReverseSolution(reverse_solution_ != paths_reversed);
#ifdef USINGZ
- if (zCallback64_) { c.SetZCallback(zCallback64_); }
+ auto fp = std::bind(&ClipperOffset::ZCB, this, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3,
+ std::placeholders::_4, std::placeholders::_5);
+ c.SetZCallback(fp);
#endif
- c.AddSubject(solution);
- if (paths_reversed)
- c.Execute(ClipType::Union, FillRule::Negative, paths);
+ c.AddSubject(*solution);
+ if (solution_tree)
+ {
+ if (paths_reversed)
+ c.Execute(ClipType::Union, FillRule::Negative, *solution_tree);
+ else
+ c.Execute(ClipType::Union, FillRule::Positive, *solution_tree);
+ }
else
- c.Execute(ClipType::Union, FillRule::Positive, paths);
+ {
+ if (paths_reversed)
+ c.Execute(ClipType::Union, FillRule::Negative, *solution);
+ else
+ c.Execute(ClipType::Union, FillRule::Positive, *solution);
+ }
+}
+
+void ClipperOffset::Execute(double delta, Paths64& paths)
+{
+ paths.clear();
+ solution = &paths;
+ solution_tree = nullptr;
+ ExecuteInternal(delta);
}
void ClipperOffset::Execute(double delta, PolyTree64& polytree)
{
polytree.Clear();
-
+ solution_tree = &polytree;
+ solution = new Paths64();
ExecuteInternal(delta);
- if (!solution.size()) return;
-
- bool paths_reversed = CheckReverseOrientation();
- //clean up self-intersections ...
- Clipper64 c;
- c.PreserveCollinear(false);
- //the solution should retain the orientation of the input
- c.ReverseSolution (reverse_solution_ != paths_reversed);
-#ifdef USINGZ
- if (zCallback64_) {
- c.SetZCallback(zCallback64_);
- }
-#endif
- c.AddSubject(solution);
-
-
- if (paths_reversed)
- c.Execute(ClipType::Union, FillRule::Negative, polytree);
- else
- c.Execute(ClipType::Union, FillRule::Positive, polytree);
+ delete solution;
+ solution = nullptr;
}
void ClipperOffset::Execute(DeltaCallback64 delta_cb, Paths64& paths)
diff --git a/thirdparty/clipper2/src/clipper.rectclip.cpp b/thirdparty/clipper2/src/clipper.rectclip.cpp
index 9aa0fc0f76..23809b5ef6 100644
--- a/thirdparty/clipper2/src/clipper.rectclip.cpp
+++ b/thirdparty/clipper2/src/clipper.rectclip.cpp
@@ -1,8 +1,8 @@
/*******************************************************************************
* Author : Angus Johnson *
-* Date : 8 September 2023 *
+* Date : 5 July 2024 *
* Website : http://www.angusj.com *
-* Copyright : Angus Johnson 2010-2023 *
+* Copyright : Angus Johnson 2010-2024 *
* Purpose : FAST rectangular clipping *
* License : http://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************/
@@ -71,7 +71,7 @@ namespace Clipper2Lib {
return pt1.y == pt2.y;
}
- inline bool GetSegmentIntersection(const Point64& p1,
+ bool GetSegmentIntersection(const Point64& p1,
const Point64& p2, const Point64& p3, const Point64& p4, Point64& ip)
{
double res1 = CrossProduct(p1, p3, p4);
@@ -113,7 +113,7 @@ namespace Clipper2Lib {
if ((res3 > 0) == (res4 > 0)) return false;
// segments must intersect to get here
- return GetIntersectPoint(p1, p2, p3, p4, ip);
+ return GetSegmentIntersectPt(p1, p2, p3, p4, ip);
}
inline bool GetIntersection(const Path64& rectPath,
@@ -125,7 +125,7 @@ namespace Clipper2Lib {
{
case Location::Left:
if (GetSegmentIntersection(p, p2, rectPath[0], rectPath[3], ip)) return true;
- else if ((p.y < rectPath[0].y) && GetSegmentIntersection(p, p2, rectPath[0], rectPath[1], ip))
+ else if ((p.y < rectPath[0].y) && GetSegmentIntersection(p, p2, rectPath[0], rectPath[1], ip))
{
loc = Location::Top;
return true;
@@ -180,7 +180,7 @@ namespace Clipper2Lib {
else return false;
default: // loc == rInside
- if (GetSegmentIntersection(p, p2, rectPath[0], rectPath[3], ip))
+ if (GetSegmentIntersection(p, p2, rectPath[0], rectPath[3], ip))
{
loc = Location::Left;
return true;
@@ -320,9 +320,9 @@ namespace Clipper2Lib {
// this method is only called by InternalExecute.
// Later splitting & rejoining won't create additional op's,
// though they will change the (non-storage) results_ count.
- int curr_idx = static_cast<int>(results_.size()) - 1;
+ size_t curr_idx = results_.size();
OutPt2* result;
- if (curr_idx < 0 || start_new)
+ if (curr_idx == 0 || start_new)
{
result = &op_container_.emplace_back(OutPt2());
result->pt = pt;
@@ -332,6 +332,7 @@ namespace Clipper2Lib {
}
else
{
+ --curr_idx;
OutPt2* prevOp = results_[curr_idx];
if (prevOp->pt == pt) return prevOp;
result = &op_container_.emplace_back(OutPt2());
@@ -349,27 +350,27 @@ namespace Clipper2Lib {
void RectClip64::AddCorner(Location prev, Location curr)
{
if (HeadingClockwise(prev, curr))
- Add(rect_as_path_[static_cast<int>(prev)]);
+ Add(rect_as_path_[static_cast<size_t>(prev)]);
else
- Add(rect_as_path_[static_cast<int>(curr)]);
+ Add(rect_as_path_[static_cast<size_t>(curr)]);
}
void RectClip64::AddCorner(Location& loc, bool isClockwise)
{
if (isClockwise)
{
- Add(rect_as_path_[static_cast<int>(loc)]);
+ Add(rect_as_path_[static_cast<size_t>(loc)]);
loc = GetAdjacentLocation(loc, true);
}
else
{
loc = GetAdjacentLocation(loc, false);
- Add(rect_as_path_[static_cast<int>(loc)]);
+ Add(rect_as_path_[static_cast<size_t>(loc)]);
}
}
void RectClip64::GetNextLocation(const Path64& path,
- Location& loc, int& i, int highI)
+ Location& loc, size_t& i, size_t highI)
{
switch (loc)
{
@@ -420,31 +421,52 @@ namespace Clipper2Lib {
break; //inner loop
}
break;
- } //switch
+ } //switch
+ }
+
+ bool StartLocsAreClockwise(const std::vector<Location>& startlocs)
+ {
+ int result = 0;
+ for (size_t i = 1; i < startlocs.size(); ++i)
+ {
+ int d = static_cast<int>(startlocs[i]) - static_cast<int>(startlocs[i - 1]);
+ switch (d)
+ {
+ case -1: result -= 1; break;
+ case 1: result += 1; break;
+ case -3: result += 1; break;
+ case 3: result -= 1; break;
+ }
+ }
+ return result > 0;
}
void RectClip64::ExecuteInternal(const Path64& path)
{
- int i = 0, highI = static_cast<int>(path.size()) - 1;
+ if (path.size() < 1)
+ return;
+
+ size_t highI = path.size() - 1;
Location prev = Location::Inside, loc;
Location crossing_loc = Location::Inside;
Location first_cross_ = Location::Inside;
if (!GetLocation(rect_, path[highI], loc))
{
- i = highI - 1;
- while (i >= 0 && !GetLocation(rect_, path[i], prev)) --i;
- if (i < 0)
+ size_t i = highI;
+ while (i > 0 && !GetLocation(rect_, path[i - 1], prev))
+ --i;
+ if (i == 0)
{
// all of path must be inside fRect
for (const auto& pt : path) Add(pt);
return;
}
if (prev == Location::Inside) loc = Location::Inside;
- i = 0;
}
- Location startingLoc = loc;
+ Location starting_loc = loc;
///////////////////////////////////////////////////
+ size_t i = 0;
while (i <= highI)
{
prev = loc;
@@ -454,12 +476,12 @@ namespace Clipper2Lib {
if (i > highI) break;
Point64 ip, ip2;
- Point64 prev_pt = (i) ?
- path[static_cast<size_t>(i - 1)] :
+ Point64 prev_pt = (i) ?
+ path[static_cast<size_t>(i - 1)] :
path[highI];
crossing_loc = loc;
- if (!GetIntersection(rect_as_path_,
+ if (!GetIntersection(rect_as_path_,
path[i], prev_pt, crossing_loc, ip))
{
// ie remaining outside
@@ -470,7 +492,7 @@ namespace Clipper2Lib {
start_locs_.push_back(prev);
prev = GetAdjacentLocation(prev, isClockw);
} while (prev != loc);
- crossing_loc = crossing_prev; // still not crossed
+ crossing_loc = crossing_prev; // still not crossed
}
else if (prev != Location::Inside && prev != loc)
{
@@ -504,7 +526,7 @@ namespace Clipper2Lib {
}
else if (prev != Location::Inside)
{
- // passing right through rect. 'ip' here will be the second
+ // passing right through rect. 'ip' here will be the second
// intersect pt but we'll also need the first intersect pt (ip2)
loc = prev;
GetIntersection(rect_as_path_, prev_pt, path[i], loc, ip2);
@@ -543,7 +565,7 @@ namespace Clipper2Lib {
if (first_cross_ == Location::Inside)
{
// path never intersects
- if (startingLoc != Location::Inside)
+ if (starting_loc != Location::Inside)
{
// path is outside rect
// but being outside, it still may not contain rect
@@ -552,11 +574,13 @@ namespace Clipper2Lib {
{
// yep, the path does fully contain rect
// so add rect to the solution
+ bool is_clockwise_path = StartLocsAreClockwise(start_locs_);
for (size_t j = 0; j < 4; ++j)
{
- Add(rect_as_path_[j]);
+ size_t k = is_clockwise_path ? j : 3 - j; // reverses result path
+ Add(rect_as_path_[k]);
// we may well need to do some splitting later, so
- AddToEdge(edges_[j * 2], results_[0]);
+ AddToEdge(edges_[k * 2], results_[0]);
}
}
}
@@ -589,8 +613,7 @@ namespace Clipper2Lib {
OutPt2* op2 = op;
do
{
- if (!CrossProduct(op2->prev->pt,
- op2->pt, op2->next->pt))
+ if (IsCollinear(op2->prev->pt, op2->pt, op2->next->pt))
{
if (op2 == op)
{
@@ -640,7 +663,7 @@ namespace Clipper2Lib {
}
}
- void RectClip64::TidyEdges(int idx, OutPt2List& cw, OutPt2List& ccw)
+ void RectClip64::TidyEdges(size_t idx, OutPt2List& cw, OutPt2List& ccw)
{
if (ccw.empty()) return;
bool isHorz = ((idx == 1) || (idx == 3));
@@ -648,7 +671,7 @@ namespace Clipper2Lib {
size_t i = 0, j = 0;
OutPt2* p1, * p2, * p1a, * p2a, * op, * op2;
- while (i < cw.size())
+ while (i < cw.size())
{
p1 = cw[i];
if (!p1 || p1->next == p1->prev)
@@ -825,8 +848,8 @@ namespace Clipper2Lib {
OutPt2* op2 = op->next;
while (op2 && op2 != op)
{
- if (CrossProduct(op2->prev->pt,
- op2->pt, op2->next->pt) == 0)
+ if (IsCollinear(op2->prev->pt,
+ op2->pt, op2->next->pt))
{
op = op2->prev;
op2 = UnlinkOp(op2);
@@ -854,7 +877,7 @@ namespace Clipper2Lib {
if (rect_.IsEmpty()) return result;
for (const Path64& path : paths)
- {
+ {
if (path.size() < 3) continue;
path_bounds_ = GetBounds(path);
if (!rect_.Intersects(path_bounds_))
@@ -868,9 +891,9 @@ namespace Clipper2Lib {
ExecuteInternal(path);
CheckEdges();
- for (int i = 0; i < 4; ++i)
+ for (size_t i = 0; i < 4; ++i)
TidyEdges(i, edges_[i * 2], edges_[i * 2 + 1]);
-
+
for (OutPt2*& op : results_)
{
Path64 tmp = GetPath(op);
@@ -925,14 +948,14 @@ namespace Clipper2Lib {
op_container_ = std::deque<OutPt2>();
start_locs_.clear();
- int i = 1, highI = static_cast<int>(path.size()) - 1;
+ size_t i = 1, highI = path.size() - 1;
Location prev = Location::Inside, loc;
Location crossing_loc;
if (!GetLocation(rect_, path[0], loc))
{
while (i <= highI && !GetLocation(rect_, path[i], prev)) ++i;
- if (i > highI)
+ if (i > highI)
{
// all of path must be inside fRect
for (const auto& pt : path) Add(pt);
@@ -953,7 +976,7 @@ namespace Clipper2Lib {
Point64 prev_pt = path[static_cast<size_t>(i - 1)];
crossing_loc = loc;
- if (!GetIntersection(rect_as_path_,
+ if (!GetIntersection(rect_as_path_,
path[i], prev_pt, crossing_loc, ip))
{
// ie remaining outside
@@ -971,10 +994,10 @@ namespace Clipper2Lib {
}
else if (prev != Location::Inside)
{
- // passing right through rect. 'ip' here will be the second
+ // passing right through rect. 'ip' here will be the second
// intersect pt but we'll also need the first intersect pt (ip2)
crossing_loc = prev;
- GetIntersection(rect_as_path_,
+ GetIntersection(rect_as_path_,
prev_pt, path[i], crossing_loc, ip2);
Add(ip2, true);
Add(ip);
@@ -991,14 +1014,14 @@ namespace Clipper2Lib {
{
Path64 result;
if (!op || op == op->next) return result;
- op = op->next; // starting at path beginning
+ op = op->next; // starting at path beginning
result.push_back(op->pt);
OutPt2 *op2 = op->next;
while (op2 != op)
{
result.push_back(op2->pt);
op2 = op2->next;
- }
+ }
return result;
}