summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/FUNDING.yml2
-rw-r--r--.lgtm.yml7
-rw-r--r--CODE_OF_CONDUCT.md4
-rw-r--r--README.md1
-rw-r--r--core/bind/core_bind.cpp152
-rw-r--r--core/bind/core_bind.h54
-rw-r--r--core/color.cpp134
-rw-r--r--core/color.h2
-rw-r--r--core/cowdata.h2
-rw-r--r--core/hashfuncs.h2
-rw-r--r--core/input/gamecontrollerdb.txt123
-rw-r--r--core/io/file_access_pack.cpp19
-rw-r--r--core/io/file_access_pack.h6
-rw-r--r--core/io/file_access_zip.cpp9
-rw-r--r--core/io/file_access_zip.h10
-rw-r--r--core/io/ip_address.cpp4
-rw-r--r--core/io/json.cpp20
-rw-r--r--core/io/json.h8
-rw-r--r--core/io/resource_loader.cpp6
-rw-r--r--core/io/xml_parser.cpp4
-rw-r--r--core/math/audio_frame.h2
-rw-r--r--core/math/expression.cpp20
-rw-r--r--core/math/expression.h2
-rw-r--r--core/math/quat.h2
-rw-r--r--core/method_bind.h14
-rw-r--r--core/os/file_access.cpp8
-rw-r--r--core/os/os.h4
-rw-r--r--core/project_settings.cpp6
-rw-r--r--core/project_settings.h2
-rw-r--r--core/register_core_types.cpp5
-rw-r--r--core/string_buffer.h24
-rw-r--r--core/string_builder.cpp4
-rw-r--r--core/string_name.cpp2
-rw-r--r--core/string_name.h2
-rw-r--r--core/type_info.h3
-rw-r--r--core/ustring.cpp1114
-rw-r--r--core/ustring.h182
-rw-r--r--core/variant.cpp4
-rw-r--r--core/variant.h5
-rw-r--r--core/variant_call.cpp63
-rw-r--r--core/variant_internal.h118
-rw-r--r--core/variant_op.cpp54
-rw-r--r--core/variant_parser.cpp30
-rw-r--r--core/variant_parser.h8
-rw-r--r--doc/classes/@GlobalScope.xml11
-rw-r--r--doc/classes/AABB.xml2
-rw-r--r--doc/classes/AnimatedSprite2D.xml1
-rw-r--r--doc/classes/Animation.xml2
-rw-r--r--doc/classes/AnimationNode.xml2
-rw-r--r--doc/classes/AnimationNodeAdd2.xml2
-rw-r--r--doc/classes/AnimationNodeAdd3.xml2
-rw-r--r--doc/classes/AnimationNodeAnimation.xml2
-rw-r--r--doc/classes/AnimationNodeBlend2.xml2
-rw-r--r--doc/classes/AnimationNodeBlend3.xml2
-rw-r--r--doc/classes/AnimationNodeBlendSpace1D.xml2
-rw-r--r--doc/classes/AnimationNodeBlendSpace2D.xml2
-rw-r--r--doc/classes/AnimationNodeBlendTree.xml2
-rw-r--r--doc/classes/AnimationNodeOneShot.xml2
-rw-r--r--doc/classes/AnimationNodeOutput.xml2
-rw-r--r--doc/classes/AnimationNodeStateMachine.xml2
-rw-r--r--doc/classes/AnimationNodeStateMachinePlayback.xml2
-rw-r--r--doc/classes/AnimationNodeStateMachineTransition.xml2
-rw-r--r--doc/classes/AnimationNodeTimeScale.xml2
-rw-r--r--doc/classes/AnimationNodeTimeSeek.xml2
-rw-r--r--doc/classes/AnimationNodeTransition.xml2
-rw-r--r--doc/classes/AnimationPlayer.xml7
-rw-r--r--doc/classes/AnimationTree.xml4
-rw-r--r--doc/classes/Area2D.xml6
-rw-r--r--doc/classes/Area3D.xml4
-rw-r--r--doc/classes/ArrayMesh.xml2
-rw-r--r--doc/classes/AudioEffectRecord.xml2
-rw-r--r--doc/classes/AudioServer.xml2
-rw-r--r--doc/classes/AudioStream.xml2
-rw-r--r--doc/classes/AudioStreamGenerator.xml2
-rw-r--r--doc/classes/AudioStreamGeneratorPlayback.xml2
-rw-r--r--doc/classes/AudioStreamPlayer.xml2
-rw-r--r--doc/classes/AudioStreamPlayer2D.xml2
-rw-r--r--doc/classes/AudioStreamPlayer3D.xml3
-rw-r--r--doc/classes/BaseMaterial3D.xml2
-rw-r--r--doc/classes/Basis.xml4
-rw-r--r--doc/classes/CPUParticles2D.xml2
-rw-r--r--doc/classes/CanvasItem.xml4
-rw-r--r--doc/classes/CanvasLayer.xml4
-rw-r--r--doc/classes/CharFXTransform.xml4
-rw-r--r--doc/classes/ClippedCamera3D.xml2
-rw-r--r--doc/classes/CollisionShape2D.xml2
-rw-r--r--doc/classes/CollisionShape3D.xml4
-rw-r--r--doc/classes/Color.xml20
-rw-r--r--doc/classes/Control.xml38
-rw-r--r--doc/classes/Dictionary.xml2
-rw-r--r--doc/classes/DirectionalLight3D.xml2
-rw-r--r--doc/classes/Directory.xml2
-rw-r--r--doc/classes/DynamicFont.xml2
-rw-r--r--doc/classes/EditorDebuggerPlugin.xml103
-rw-r--r--doc/classes/EditorExportPlugin.xml12
-rw-r--r--doc/classes/EditorFeatureProfile.xml10
-rw-r--r--doc/classes/EditorImportPlugin.xml2
-rw-r--r--doc/classes/EditorNode3DGizmoPlugin.xml2
-rw-r--r--doc/classes/EditorPlugin.xml20
-rw-r--r--doc/classes/EditorScenePostImport.xml2
-rw-r--r--doc/classes/EngineDebugger.xml132
-rw-r--r--doc/classes/Environment.xml69
-rw-r--r--doc/classes/Expression.xml2
-rw-r--r--doc/classes/File.xml10
-rw-r--r--doc/classes/FileDialog.xml1
-rw-r--r--doc/classes/Font.xml2
-rw-r--r--doc/classes/GIProbe.xml2
-rw-r--r--doc/classes/GPUParticles2D.xml4
-rw-r--r--doc/classes/GPUParticles3D.xml4
-rw-r--r--doc/classes/GridContainer.xml7
-rw-r--r--doc/classes/HTTPClient.xml9
-rw-r--r--doc/classes/HTTPRequest.xml5
-rw-r--r--doc/classes/Input.xml17
-rw-r--r--doc/classes/InputEvent.xml4
-rw-r--r--doc/classes/InputEventAction.xml2
-rw-r--r--doc/classes/InputEventJoypadButton.xml2
-rw-r--r--doc/classes/InputEventJoypadMotion.xml2
-rw-r--r--doc/classes/InputEventKey.xml2
-rw-r--r--doc/classes/InputEventMouse.xml2
-rw-r--r--doc/classes/InputEventMouseButton.xml2
-rw-r--r--doc/classes/InputEventMouseMotion.xml2
-rw-r--r--doc/classes/InputEventScreenDrag.xml2
-rw-r--r--doc/classes/InputEventScreenTouch.xml2
-rw-r--r--doc/classes/InputEventWithModifiers.xml2
-rw-r--r--doc/classes/InputMap.xml2
-rw-r--r--doc/classes/JavaScript.xml2
-rw-r--r--doc/classes/KinematicBody2D.xml2
-rw-r--r--doc/classes/KinematicBody3D.xml2
-rw-r--r--doc/classes/Light2D.xml2
-rw-r--r--doc/classes/Light3D.xml10
-rw-r--r--doc/classes/LightOccluder2D.xml2
-rw-r--r--doc/classes/MeshInstance2D.xml2
-rw-r--r--doc/classes/MultiMesh.xml4
-rw-r--r--doc/classes/MultiMeshInstance3D.xml6
-rw-r--r--doc/classes/Mutex.xml2
-rw-r--r--doc/classes/NetworkedMultiplayerPeer.xml2
-rw-r--r--doc/classes/Node.xml5
-rw-r--r--doc/classes/Node2D.xml2
-rw-r--r--doc/classes/Node3D.xml2
-rw-r--r--doc/classes/Object.xml4
-rw-r--r--doc/classes/OmniLight3D.xml2
-rw-r--r--doc/classes/OptionButton.xml2
-rw-r--r--doc/classes/PackedByteArray.xml18
-rw-r--r--doc/classes/PhysicsBody2D.xml6
-rw-r--r--doc/classes/PhysicsBody3D.xml6
-rw-r--r--doc/classes/PhysicsDirectBodyState2D.xml2
-rw-r--r--doc/classes/PhysicsDirectSpaceState2D.xml2
-rw-r--r--doc/classes/PhysicsDirectSpaceState3D.xml2
-rw-r--r--doc/classes/PhysicsShapeQueryParameters2D.xml2
-rw-r--r--doc/classes/PhysicsShapeQueryParameters3D.xml2
-rw-r--r--doc/classes/Plane.xml2
-rw-r--r--doc/classes/PopupMenu.xml2
-rw-r--r--doc/classes/ProjectSettings.xml19
-rw-r--r--doc/classes/Quat.xml2
-rw-r--r--doc/classes/RayCast2D.xml4
-rw-r--r--doc/classes/RayCast3D.xml4
-rw-r--r--doc/classes/Rect2.xml2
-rw-r--r--doc/classes/Rect2i.xml2
-rw-r--r--doc/classes/ReflectionProbe.xml2
-rw-r--r--doc/classes/RenderingServer.xml51
-rw-r--r--doc/classes/RichTextEffect.xml4
-rw-r--r--doc/classes/RichTextLabel.xml2
-rw-r--r--doc/classes/RigidBody2D.xml2
-rw-r--r--doc/classes/RigidBody3D.xml4
-rw-r--r--doc/classes/SceneTree.xml4
-rw-r--r--doc/classes/Script.xml2
-rw-r--r--doc/classes/Semaphore.xml2
-rw-r--r--doc/classes/Shader.xml4
-rw-r--r--doc/classes/ShaderMaterial.xml2
-rw-r--r--doc/classes/Shape2D.xml2
-rw-r--r--doc/classes/Shape3D.xml2
-rw-r--r--doc/classes/Skeleton2D.xml2
-rw-r--r--doc/classes/SoftBody3D.xml6
-rw-r--r--doc/classes/SpotLight3D.xml2
-rw-r--r--doc/classes/SpringArm3D.xml2
-rw-r--r--doc/classes/Sprite2D.xml4
-rw-r--r--doc/classes/Sprite3D.xml4
-rw-r--r--doc/classes/SpriteFrames.xml1
-rw-r--r--doc/classes/StreamPeerSSL.xml2
-rw-r--r--doc/classes/String.xml51
-rw-r--r--doc/classes/SubViewport.xml1
-rw-r--r--doc/classes/TextEdit.xml4
-rw-r--r--doc/classes/Texture2D.xml2
-rw-r--r--doc/classes/Theme.xml2
-rw-r--r--doc/classes/Thread.xml3
-rw-r--r--doc/classes/TileMap.xml8
-rw-r--r--doc/classes/TouchScreenButton.xml6
-rw-r--r--doc/classes/Transform.xml6
-rw-r--r--doc/classes/Transform2D.xml2
-rw-r--r--doc/classes/Translation.xml4
-rw-r--r--doc/classes/TranslationServer.xml4
-rw-r--r--doc/classes/Variant.xml2
-rw-r--r--doc/classes/Vector2.xml2
-rw-r--r--doc/classes/Vector2i.xml2
-rw-r--r--doc/classes/Vector3.xml2
-rw-r--r--doc/classes/Vector3i.xml2
-rw-r--r--doc/classes/Viewport.xml4
-rw-r--r--doc/classes/VisualShader.xml6
-rw-r--r--doc/classes/VisualShaderNode.xml2
-rw-r--r--doc/classes/VisualShaderNodeCustom.xml6
-rw-r--r--doc/classes/VisualShaderNodeInput.xml2
-rw-r--r--doc/classes/World2D.xml2
-rw-r--r--doc/classes/World3D.xml2
-rw-r--r--doc/classes/WorldEnvironment.xml2
-rw-r--r--doc/classes/XRCamera3D.xml2
-rw-r--r--doc/classes/XRController3D.xml2
-rw-r--r--doc/classes/XRInterface.xml2
-rw-r--r--doc/classes/XROrigin3D.xml2
-rw-r--r--doc/classes/XRPositionalTracker.xml2
-rw-r--r--doc/classes/XRServer.xml2
-rw-r--r--drivers/alsa/audio_driver_alsa.h8
-rw-r--r--drivers/alsamidi/midi_driver_alsamidi.h7
-rw-r--r--drivers/dummy/rasterizer_dummy.h1
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.h8
-rw-r--r--drivers/unix/file_access_unix.cpp2
-rw-r--r--drivers/unix/os_unix.cpp35
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp20
-rw-r--r--drivers/windows/dir_access_windows.cpp132
-rw-r--r--drivers/windows/file_access_windows.cpp57
-rw-r--r--editor/connections_dialog.cpp2
-rw-r--r--editor/debugger/editor_debugger_node.cpp27
-rw-r--r--editor/debugger/editor_debugger_node.h5
-rw-r--r--editor/debugger/script_editor_debugger.cpp63
-rw-r--r--editor/debugger/script_editor_debugger.h15
-rw-r--r--editor/editor_audio_buses.h2
-rw-r--r--editor/editor_data.cpp10
-rw-r--r--editor/editor_feature_profile.cpp19
-rw-r--r--editor/editor_feature_profile.h2
-rw-r--r--editor/editor_help.cpp16
-rw-r--r--editor/editor_inspector.cpp11
-rw-r--r--editor/editor_inspector.h1
-rw-r--r--editor/editor_node.cpp13
-rw-r--r--editor/editor_plugin.cpp10
-rw-r--r--editor/editor_plugin.h4
-rw-r--r--editor/editor_properties.cpp10
-rw-r--r--editor/editor_run.cpp4
-rw-r--r--editor/editor_run_native.cpp2
-rw-r--r--editor/editor_sectioned_inspector.cpp2
-rw-r--r--editor/editor_settings.cpp2
-rw-r--r--editor/filesystem_dock.cpp2
-rw-r--r--editor/find_in_files.cpp4
-rw-r--r--editor/input_map_editor.cpp2
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp2
-rw-r--r--editor/plugins/debugger_editor_plugin.cpp32
-rw-r--r--editor/plugins/editor_debugger_plugin.cpp124
-rw-r--r--editor/plugins/editor_debugger_plugin.h64
-rw-r--r--editor/plugins/editor_preview_plugins.cpp4
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp7
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp2
-rw-r--r--editor/plugins/theme_editor_plugin.cpp6
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp292
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h8
-rw-r--r--editor/project_manager.cpp574
-rw-r--r--editor/project_manager.h78
-rw-r--r--editor/project_settings_editor.cpp1
-rw-r--r--editor/script_create_dialog.cpp10
-rw-r--r--editor/settings_config_dialog.cpp2
-rw-r--r--editor/translations/af.po10
-rw-r--r--editor/translations/ar.po810
-rw-r--r--editor/translations/bg.po8
-rw-r--r--editor/translations/bn.po10
-rw-r--r--editor/translations/ca.po10
-rw-r--r--editor/translations/cs.po16
-rw-r--r--editor/translations/da.po10
-rw-r--r--editor/translations/de.po59
-rw-r--r--editor/translations/editor.pot8
-rw-r--r--editor/translations/el.po10
-rw-r--r--editor/translations/eo.po8
-rw-r--r--editor/translations/es.po10
-rw-r--r--editor/translations/es_AR.po10
-rw-r--r--editor/translations/et.po259
-rw-r--r--editor/translations/eu.po10
-rw-r--r--editor/translations/fa.po10
-rw-r--r--editor/translations/fi.po10
-rw-r--r--editor/translations/fil.po47
-rw-r--r--editor/translations/fr.po10
-rw-r--r--editor/translations/ga.po8
-rw-r--r--editor/translations/he.po777
-rw-r--r--editor/translations/hi.po10
-rw-r--r--editor/translations/hr.po10
-rw-r--r--editor/translations/hu.po10
-rw-r--r--editor/translations/id.po32
-rw-r--r--editor/translations/is.po8
-rw-r--r--editor/translations/it.po29
-rw-r--r--editor/translations/ja.po30
-rw-r--r--editor/translations/ka.po10
-rw-r--r--editor/translations/ko.po10
-rw-r--r--editor/translations/lt.po8
-rw-r--r--editor/translations/lv.po10
-rw-r--r--editor/translations/mi.po8
-rw-r--r--editor/translations/ml.po8
-rw-r--r--editor/translations/mr.po8
-rw-r--r--editor/translations/ms.po1141
-rw-r--r--editor/translations/nb.po10
-rw-r--r--editor/translations/nl.po29
-rw-r--r--editor/translations/or.po8
-rw-r--r--editor/translations/pl.po19
-rw-r--r--editor/translations/pr.po8
-rw-r--r--editor/translations/pt_BR.po10
-rw-r--r--editor/translations/pt_PT.po84
-rw-r--r--editor/translations/ro.po10
-rw-r--r--editor/translations/ru.po29
-rw-r--r--editor/translations/si.po8
-rw-r--r--editor/translations/sk.po828
-rw-r--r--editor/translations/sl.po10
-rw-r--r--editor/translations/sq.po10
-rw-r--r--editor/translations/sr_Cyrl.po10
-rw-r--r--editor/translations/sr_Latn.po8
-rw-r--r--editor/translations/sv.po24
-rw-r--r--editor/translations/ta.po30
-rw-r--r--editor/translations/te.po8
-rw-r--r--editor/translations/th.po36
-rw-r--r--editor/translations/tr.po34
-rw-r--r--editor/translations/uk.po10
-rw-r--r--editor/translations/ur_PK.po8
-rw-r--r--editor/translations/vi.po10
-rw-r--r--editor/translations/zh_CN.po23
-rw-r--r--editor/translations/zh_HK.po10
-rw-r--r--editor/translations/zh_TW.po10
-rw-r--r--main/main.cpp29
-rw-r--r--methods.py11
-rw-r--r--modules/arkit/register_types.h5
-rw-r--r--modules/basis_universal/texture_basisu.h5
-rw-r--r--modules/camera/register_types.h5
-rw-r--r--modules/csg/doc_classes/CSGShape3D.xml4
-rw-r--r--modules/cvtt/register_types.h8
-rw-r--r--modules/denoise/register_types.h5
-rw-r--r--modules/enet/doc_classes/NetworkedMultiplayerENet.xml4
-rw-r--r--modules/gdnative/doc_classes/GDNativeLibrary.xml4
-rw-r--r--modules/gdnative/gdnative/string.cpp649
-rw-r--r--modules/gdnative/gdnative_api.json390
-rw-r--r--modules/gdnative/include/gdnative/string.h158
-rw-r--r--modules/gdnative/nativescript/api_generator.cpp4
-rw-r--r--modules/gdscript/SCsub4
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml4
-rw-r--r--modules/gdscript/doc_classes/GDScript.xml2
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp38
-rw-r--r--modules/gdscript/gdscript.cpp4
-rw-r--r--modules/gdscript/gdscript.h1
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp148
-rw-r--r--modules/gdscript/gdscript_analyzer.h6
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp736
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h277
-rw-r--r--modules/gdscript/gdscript_cache.cpp14
-rw-r--r--modules/gdscript/gdscript_cache.h6
-rw-r--r--modules/gdscript/gdscript_codegen.h160
-rw-r--r--modules/gdscript/gdscript_compiler.cpp2680
-rw-r--r--modules/gdscript/gdscript_compiler.h158
-rw-r--r--modules/gdscript/gdscript_editor.cpp35
-rw-r--r--modules/gdscript/gdscript_function.cpp523
-rw-r--r--modules/gdscript/gdscript_function.h13
-rw-r--r--modules/gdscript/gdscript_functions.cpp2
-rw-r--r--modules/gdscript/gdscript_parser.cpp30
-rw-r--r--modules/gdscript/gdscript_parser.h2
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp80
-rw-r--r--modules/gdscript/gdscript_tokenizer.h22
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp6
-rw-r--r--modules/gdscript/register_types.cpp28
-rw-r--r--modules/gdscript/tests/test_gdscript.cpp (renamed from tests/test_gdscript.cpp)88
-rw-r--r--modules/gdscript/tests/test_gdscript.h (renamed from tests/test_gdscript.h)5
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml4
-rw-r--r--modules/mono/build_scripts/mono_reg_utils.py10
-rw-r--r--modules/mono/doc_classes/CSharpScript.xml2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs10
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs5
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs17
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/CsProjOperations.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs21
-rw-r--r--modules/mono/editor/godotsharp_export.cpp41
-rw-r--r--modules/mono/editor/script_class_parser.cpp8
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs133
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp8
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp38
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h26
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h21
-rw-r--r--modules/mono/register_types.h5
-rw-r--r--modules/mono/utils/macros.h2
-rw-r--r--modules/mono/utils/mono_reg_utils.cpp8
-rw-r--r--modules/mono/utils/path_utils.cpp26
-rw-r--r--modules/mono/utils/string_utils.cpp6
-rw-r--r--modules/regex/regex.cpp229
-rw-r--r--modules/visual_script/doc_classes/VisualScript.xml2
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp2
-rw-r--r--modules/visual_script/visual_script_expression.cpp14
-rw-r--r--modules/visual_script/visual_script_nodes.cpp52
-rw-r--r--modules/webrtc/webrtc_data_channel_gdnative.h8
-rw-r--r--modules/webrtc/webrtc_data_channel_js.h8
-rw-r--r--modules/webrtc/webrtc_multiplayer.h2
-rw-r--r--modules/webrtc/webrtc_peer_connection_gdnative.h8
-rw-r--r--platform/android/export/export.cpp8
-rw-r--r--platform/android/java/lib/res/values/dimens.xml4
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java46
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java80
-rw-r--r--platform/iphone/display_server_iphone.mm4
-rw-r--r--platform/iphone/export/export.cpp2
-rw-r--r--platform/iphone/in_app_store.mm2
-rw-r--r--platform/iphone/ios.mm2
-rw-r--r--platform/iphone/os_iphone.mm4
-rw-r--r--platform/linuxbsd/crash_handler_linuxbsd.cpp4
-rw-r--r--platform/linuxbsd/display_server_x11.cpp344
-rw-r--r--platform/linuxbsd/display_server_x11.h6
-rw-r--r--platform/osx/crash_handler_osx.mm4
-rw-r--r--platform/osx/display_server_osx.h1
-rw-r--r--platform/osx/display_server_osx.mm11
-rw-r--r--platform/osx/export/export.cpp2
-rw-r--r--platform/uwp/os_uwp.cpp8
-rw-r--r--platform/windows/crash_handler_windows.cpp2
-rw-r--r--platform/windows/detect.py18
-rw-r--r--platform/windows/display_server_windows.cpp87
-rw-r--r--platform/windows/display_server_windows.h2
-rw-r--r--platform/windows/os_windows.cpp61
-rw-r--r--platform_methods.py2
-rw-r--r--scene/2d/camera_2d.cpp18
-rw-r--r--scene/2d/camera_2d.h2
-rw-r--r--scene/2d/sprite_2d.cpp2
-rw-r--r--scene/3d/collision_shape_3d.cpp23
-rw-r--r--scene/3d/collision_shape_3d.h2
-rw-r--r--scene/3d/gpu_particles_3d.cpp52
-rw-r--r--scene/3d/gpu_particles_3d.h17
-rw-r--r--scene/3d/soft_body_3d.cpp2
-rw-r--r--scene/3d/soft_body_3d.h2
-rw-r--r--scene/3d/sprite_3d.cpp2
-rw-r--r--scene/gui/base_button.cpp2
-rw-r--r--scene/gui/label.cpp30
-rw-r--r--scene/gui/line_edit.cpp16
-rw-r--r--scene/gui/popup.cpp90
-rw-r--r--scene/gui/popup.h9
-rw-r--r--scene/gui/popup_menu.cpp369
-rw-r--r--scene/gui/popup_menu.h19
-rw-r--r--scene/gui/rich_text_effect.h4
-rw-r--r--scene/gui/rich_text_label.cpp6
-rw-r--r--scene/gui/text_edit.cpp90
-rw-r--r--scene/gui/text_edit.h4
-rw-r--r--scene/main/canvas_item.cpp4
-rw-r--r--scene/main/node.cpp7
-rw-r--r--scene/main/window.cpp5
-rw-r--r--scene/resources/dynamic_font.cpp16
-rw-r--r--scene/resources/dynamic_font.h16
-rw-r--r--scene/resources/font.cpp26
-rw-r--r--scene/resources/font.h26
-rw-r--r--scene/resources/mesh.h1
-rw-r--r--scene/resources/particles_material.cpp279
-rw-r--r--scene/resources/particles_material.h64
-rw-r--r--scene/resources/shader.cpp2
-rw-r--r--scene/resources/style_box.cpp1
-rw-r--r--scene/resources/syntax_highlighter.cpp35
-rw-r--r--scene/resources/texture.h3
-rw-r--r--scene/resources/tile_set.cpp4
-rw-r--r--scene/resources/visual_shader.cpp83
-rw-r--r--scene/resources/visual_shader.h33
-rw-r--r--scene/resources/visual_shader_nodes.cpp55
-rw-r--r--scene/resources/visual_shader_nodes.h96
-rw-r--r--servers/display_server.cpp4
-rw-r--r--servers/display_server.h1
-rw-r--r--servers/physics_2d/body_pair_2d_sw.cpp4
-rw-r--r--servers/physics_server_2d.h2
-rw-r--r--servers/physics_server_3d.h2
-rw-r--r--servers/rendering/rasterizer.h7
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp95
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_effects_rd.h29
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_rd.cpp2
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp76
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp9
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_scene_rd.h6
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp1043
-rw-r--r--servers/rendering/rasterizer_rd/rasterizer_storage_rd.h351
-rw-r--r--servers/rendering/rasterizer_rd/shader_compiler_rd.cpp14
-rw-r--r--servers/rendering/rasterizer_rd/shader_compiler_rd.h3
-rw-r--r--servers/rendering/rasterizer_rd/shaders/SCsub3
-rw-r--r--servers/rendering/rasterizer_rd/shaders/copy.glsl42
-rw-r--r--servers/rendering/rasterizer_rd/shaders/particles.glsl394
-rw-r--r--servers/rendering/rasterizer_rd/shaders/particles_copy.glsl82
-rw-r--r--servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl8
-rw-r--r--servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl2
-rw-r--r--servers/rendering/rasterizer_rd/shaders/sort.glsl203
-rw-r--r--servers/rendering/rendering_server_canvas.cpp13
-rw-r--r--servers/rendering/rendering_server_raster.h3
-rw-r--r--servers/rendering/rendering_server_scene.cpp1
-rw-r--r--servers/rendering/rendering_server_wrap_mt.h4
-rw-r--r--servers/rendering/shader_language.cpp267
-rw-r--r--servers/rendering/shader_language.h31
-rw-r--r--servers/rendering/shader_types.cpp49
-rw-r--r--servers/rendering_server.cpp1
-rw-r--r--servers/rendering_server.h17
-rw-r--r--servers/text_server.h0
-rw-r--r--tests/SCsub4
-rw-r--r--tests/test_color.h8
-rw-r--r--tests/test_expression.h431
-rw-r--r--tests/test_gdnative_string.h1985
-rw-r--r--tests/test_macros.cpp42
-rw-r--r--tests/test_macros.h16
-rw-r--r--tests/test_main.cpp55
-rw-r--r--tests/test_math.cpp8
-rw-r--r--tests/test_shader_lang.cpp2
-rw-r--r--tests/test_string.h570
499 files changed, 17095 insertions, 7773 deletions
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
deleted file mode 100644
index 0820ab175d..0000000000
--- a/.github/FUNDING.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-patreon: godotengine
-custom: https://godotengine.org/donate
diff --git a/.lgtm.yml b/.lgtm.yml
new file mode 100644
index 0000000000..e4841eaff4
--- /dev/null
+++ b/.lgtm.yml
@@ -0,0 +1,7 @@
+extraction:
+ cpp:
+ after_prepare:
+ - pip3 install scons
+ - PATH="/opt/work/.local/bin:$PATH"
+ index:
+ build_command: scons -j2
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
deleted file mode 100644
index f10438769d..0000000000
--- a/CODE_OF_CONDUCT.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# Code of Conduct
-
-By participating in this repository, you agree to abide by the
-[Godot Engine Code of Conduct](https://godotengine.org/code-of-conduct).
diff --git a/README.md b/README.md
index ad0fe3079c..1f2aa00f08 100644
--- a/README.md
+++ b/README.md
@@ -72,7 +72,6 @@ provided by the community, such as text and video tutorials, demos, etc.
Consult the [community channels](https://godotengine.org/community)
for more information.
-[![Actions Build Status](https://github.com/godotengine/godot/workflows/Godot/badge.svg?branch=master)](https://github.com/godotengine/godot/actions)
[![Code Triagers Badge](https://www.codetriage.com/godotengine/godot/badges/users.svg)](https://www.codetriage.com/godotengine/godot)
[![Translate on Weblate](https://hosted.weblate.org/widgets/godot-engine/-/godot/svg-badge.svg)](https://hosted.weblate.org/engage/godot-engine/?utm_source=widget)
[![Total alerts on LGTM](https://img.shields.io/lgtm/alerts/g/godotengine/godot.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/godotengine/godot/alerts)
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index 045d7d5872..489ff762c9 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -31,6 +31,7 @@
#include "core_bind.h"
#include "core/crypto/crypto_core.h"
+#include "core/debugger/engine_debugger.h"
#include "core/io/file_access_compressed.h"
#include "core/io/file_access_encrypted.h"
#include "core/io/json.h"
@@ -2467,3 +2468,154 @@ Ref<JSONParseResult> _JSON::parse(const String &p_json) {
}
_JSON *_JSON::singleton = nullptr;
+
+////// _EngineDebugger //////
+
+void _EngineDebugger::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("is_active"), &_EngineDebugger::is_active);
+
+ ClassDB::bind_method(D_METHOD("register_profiler", "name", "toggle", "add", "tick"), &_EngineDebugger::register_profiler);
+ ClassDB::bind_method(D_METHOD("unregister_profiler", "name"), &_EngineDebugger::unregister_profiler);
+ ClassDB::bind_method(D_METHOD("is_profiling", "name"), &_EngineDebugger::is_profiling);
+ ClassDB::bind_method(D_METHOD("has_profiler", "name"), &_EngineDebugger::has_profiler);
+
+ ClassDB::bind_method(D_METHOD("profiler_add_frame_data", "name", "data"), &_EngineDebugger::profiler_add_frame_data);
+ ClassDB::bind_method(D_METHOD("profiler_enable", "name", "enable", "arguments"), &_EngineDebugger::profiler_enable, DEFVAL(Array()));
+
+ ClassDB::bind_method(D_METHOD("register_message_capture", "name", "callable"), &_EngineDebugger::register_message_capture);
+ ClassDB::bind_method(D_METHOD("unregister_message_capture", "name"), &_EngineDebugger::unregister_message_capture);
+ ClassDB::bind_method(D_METHOD("has_capture", "name"), &_EngineDebugger::has_capture);
+
+ ClassDB::bind_method(D_METHOD("send_message", "message", "data"), &_EngineDebugger::send_message);
+}
+
+bool _EngineDebugger::is_active() {
+ return EngineDebugger::is_active();
+}
+
+void _EngineDebugger::register_profiler(const StringName &p_name, const Callable &p_toggle, const Callable &p_add, const Callable &p_tick) {
+ ERR_FAIL_COND_MSG(profilers.has(p_name) || has_profiler(p_name), "Profiler already registered: " + p_name);
+ profilers.insert(p_name, ProfilerCallable(p_toggle, p_add, p_tick));
+ ProfilerCallable &p = profilers[p_name];
+ EngineDebugger::Profiler profiler(
+ &p,
+ &_EngineDebugger::call_toggle,
+ &_EngineDebugger::call_add,
+ &_EngineDebugger::call_tick);
+ EngineDebugger::register_profiler(p_name, profiler);
+}
+
+void _EngineDebugger::unregister_profiler(const StringName &p_name) {
+ ERR_FAIL_COND_MSG(!profilers.has(p_name), "Profiler not registered: " + p_name);
+ EngineDebugger::unregister_profiler(p_name);
+ profilers.erase(p_name);
+}
+
+bool _EngineDebugger::_EngineDebugger::is_profiling(const StringName &p_name) {
+ return EngineDebugger::is_profiling(p_name);
+}
+
+bool _EngineDebugger::has_profiler(const StringName &p_name) {
+ return EngineDebugger::has_profiler(p_name);
+}
+
+void _EngineDebugger::profiler_add_frame_data(const StringName &p_name, const Array &p_data) {
+ EngineDebugger::profiler_add_frame_data(p_name, p_data);
+}
+
+void _EngineDebugger::profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts) {
+ if (EngineDebugger::get_singleton()) {
+ EngineDebugger::get_singleton()->profiler_enable(p_name, p_enabled, p_opts);
+ }
+}
+
+void _EngineDebugger::register_message_capture(const StringName &p_name, const Callable &p_callable) {
+ ERR_FAIL_COND_MSG(captures.has(p_name) || has_capture(p_name), "Capture already registered: " + p_name);
+ captures.insert(p_name, p_callable);
+ Callable &c = captures[p_name];
+ EngineDebugger::Capture capture(&c, &_EngineDebugger::call_capture);
+ EngineDebugger::register_message_capture(p_name, capture);
+}
+
+void _EngineDebugger::unregister_message_capture(const StringName &p_name) {
+ ERR_FAIL_COND_MSG(!captures.has(p_name), "Capture not registered: " + p_name);
+ EngineDebugger::unregister_message_capture(p_name);
+ captures.erase(p_name);
+}
+
+bool _EngineDebugger::has_capture(const StringName &p_name) {
+ return EngineDebugger::has_capture(p_name);
+}
+
+void _EngineDebugger::send_message(const String &p_msg, const Array &p_data) {
+ ERR_FAIL_COND_MSG(!EngineDebugger::is_active(), "Can't send message. No active debugger");
+ EngineDebugger::get_singleton()->send_message(p_msg, p_data);
+}
+
+void _EngineDebugger::call_toggle(void *p_user, bool p_enable, const Array &p_opts) {
+ Callable &toggle = ((ProfilerCallable *)p_user)->callable_toggle;
+ if (toggle.is_null()) {
+ return;
+ }
+ Variant enable = p_enable, opts = p_opts;
+ const Variant *args[2] = { &enable, &opts };
+ Variant retval;
+ Callable::CallError err;
+ toggle.call(args, 2, retval, err);
+ ERR_FAIL_COND_MSG(err.error != Callable::CallError::CALL_OK, "Error calling 'toggle' to callable: " + Variant::get_callable_error_text(toggle, args, 2, err));
+}
+
+void _EngineDebugger::call_add(void *p_user, const Array &p_data) {
+ Callable &add = ((ProfilerCallable *)p_user)->callable_add;
+ if (add.is_null()) {
+ return;
+ }
+ Variant data = p_data;
+ const Variant *args[1] = { &data };
+ Variant retval;
+ Callable::CallError err;
+ add.call(args, 1, retval, err);
+ ERR_FAIL_COND_MSG(err.error != Callable::CallError::CALL_OK, "Error calling 'add' to callable: " + Variant::get_callable_error_text(add, args, 1, err));
+}
+
+void _EngineDebugger::call_tick(void *p_user, float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) {
+ Callable &tick = ((ProfilerCallable *)p_user)->callable_tick;
+ if (tick.is_null()) {
+ return;
+ }
+ Variant frame_time = p_frame_time, idle_time = p_idle_time, physics_time = p_physics_time, physics_frame_time = p_physics_frame_time;
+ const Variant *args[4] = { &frame_time, &idle_time, &physics_time, &physics_frame_time };
+ Variant retval;
+ Callable::CallError err;
+ tick.call(args, 4, retval, err);
+ ERR_FAIL_COND_MSG(err.error != Callable::CallError::CALL_OK, "Error calling 'tick' to callable: " + Variant::get_callable_error_text(tick, args, 4, err));
+}
+
+Error _EngineDebugger::call_capture(void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured) {
+ Callable &capture = *(Callable *)p_user;
+ if (capture.is_null()) {
+ return FAILED;
+ }
+ Variant cmd = p_cmd, data = p_data;
+ const Variant *args[2] = { &cmd, &data };
+ Variant retval;
+ Callable::CallError err;
+ capture.call(args, 2, retval, err);
+ ERR_FAIL_COND_V_MSG(err.error != Callable::CallError::CALL_OK, FAILED, "Error calling 'capture' to callable: " + Variant::get_callable_error_text(capture, args, 2, err));
+ ERR_FAIL_COND_V_MSG(retval.get_type() != Variant::BOOL, FAILED, "Error calling 'capture' to callable: " + String(capture) + ". Return type is not bool.");
+ r_captured = retval;
+ return OK;
+}
+
+_EngineDebugger::~_EngineDebugger() {
+ for (Map<StringName, Callable>::Element *E = captures.front(); E; E = E->next()) {
+ EngineDebugger::unregister_message_capture(E->key());
+ }
+ captures.clear();
+ for (Map<StringName, ProfilerCallable>::Element *E = profilers.front(); E; E = E->next()) {
+ EngineDebugger::unregister_profiler(E->key());
+ }
+ profilers.clear();
+}
+
+_EngineDebugger *_EngineDebugger::singleton = nullptr;
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index a1fedf1bb8..a59fcda60c 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -715,4 +715,58 @@ public:
_JSON() { singleton = this; }
};
+class _EngineDebugger : public Object {
+ GDCLASS(_EngineDebugger, Object);
+
+ class ProfilerCallable {
+ friend class _EngineDebugger;
+
+ Callable callable_toggle;
+ Callable callable_add;
+ Callable callable_tick;
+
+ public:
+ ProfilerCallable() {}
+
+ ProfilerCallable(const Callable &p_toggle, const Callable &p_add, const Callable &p_tick) {
+ callable_toggle = p_toggle;
+ callable_add = p_add;
+ callable_tick = p_tick;
+ }
+ };
+
+ Map<StringName, Callable> captures;
+ Map<StringName, ProfilerCallable> profilers;
+
+protected:
+ static void _bind_methods();
+ static _EngineDebugger *singleton;
+
+public:
+ static _EngineDebugger *get_singleton() { return singleton; }
+
+ bool is_active();
+
+ void register_profiler(const StringName &p_name, const Callable &p_toggle, const Callable &p_add, const Callable &p_tick);
+ void unregister_profiler(const StringName &p_name);
+ bool is_profiling(const StringName &p_name);
+ bool has_profiler(const StringName &p_name);
+ void profiler_add_frame_data(const StringName &p_name, const Array &p_data);
+ void profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts = Array());
+
+ void register_message_capture(const StringName &p_name, const Callable &p_callable);
+ void unregister_message_capture(const StringName &p_name);
+ bool has_capture(const StringName &p_name);
+
+ void send_message(const String &p_msg, const Array &p_data);
+
+ static void call_toggle(void *p_user, bool p_enable, const Array &p_opts);
+ static void call_add(void *p_user, const Array &p_data);
+ static void call_tick(void *p_user, float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time);
+ static Error call_capture(void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured);
+
+ _EngineDebugger() { singleton = this; }
+ ~_EngineDebugger();
+};
+
#endif // CORE_BIND_H
diff --git a/core/color.cpp b/core/color.cpp
index 27a2d0af5c..c61ee0e64a 100644
--- a/core/color.cpp
+++ b/core/color.cpp
@@ -261,33 +261,21 @@ Color Color::from_rgbe9995(uint32_t p_rgbe) {
return Color(rd, gd, bd, 1.0f);
}
-static float _parse_col(const String &p_str, int p_ofs) {
- int ig = 0;
-
- for (int i = 0; i < 2; i++) {
- int c = p_str[i + p_ofs];
- int v = 0;
-
- if (c >= '0' && c <= '9') {
- v = c - '0';
- } else if (c >= 'a' && c <= 'f') {
- v = c - 'a';
- v += 10;
- } else if (c >= 'A' && c <= 'F') {
- v = c - 'A';
- v += 10;
- } else {
- return -1;
- }
-
- if (i == 0) {
- ig += v * 16;
- } else {
- ig += v;
- }
+static int _parse_col4(const String &p_str, int p_ofs) {
+ char character = p_str[p_ofs];
+
+ if (character >= '0' && character <= '9') {
+ return character - '0';
+ } else if (character >= 'a' && character <= 'f') {
+ return character + (10 - 'a');
+ } else if (character >= 'A' && character <= 'F') {
+ return character + (10 - 'A');
}
+ return -1;
+}
- return ig;
+static int _parse_col8(const String &p_str, int p_ofs) {
+ return _parse_col4(p_str, p_ofs) * 16 + _parse_col4(p_str, p_ofs + 1);
}
Color Color::inverted() const {
@@ -302,49 +290,54 @@ Color Color::contrasted() const {
return c;
}
-Color Color::html(const String &p_color) {
- String color = p_color;
+Color Color::html(const String &p_rgba) {
+ String color = p_rgba;
if (color.length() == 0) {
return Color();
}
if (color[0] == '#') {
- color = color.substr(1, color.length() - 1);
- }
- if (color.length() == 3 || color.length() == 4) {
- String exp_color;
- for (int i = 0; i < color.length(); i++) {
- exp_color += color[i];
- exp_color += color[i];
- }
- color = exp_color;
+ color = color.substr(1);
}
+ // If enabled, use 1 hex digit per channel instead of 2.
+ // Other sizes aren't in the HTML/CSS spec but we could add them if desired.
+ bool is_shorthand = color.length() < 5;
bool alpha = false;
if (color.length() == 8) {
alpha = true;
} else if (color.length() == 6) {
alpha = false;
+ } else if (color.length() == 4) {
+ alpha = true;
+ } else if (color.length() == 3) {
+ alpha = false;
} else {
- ERR_FAIL_V_MSG(Color(), "Invalid color code: " + p_color + ".");
+ ERR_FAIL_V_MSG(Color(), "Invalid color code: " + p_rgba + ".");
}
- int a = 255;
- if (alpha) {
- a = _parse_col(color, 0);
- ERR_FAIL_COND_V_MSG(a < 0, Color(), "Invalid color code: " + p_color + ".");
+ float r, g, b, a = 1.0;
+ if (is_shorthand) {
+ r = _parse_col4(color, 0) / 15.0;
+ g = _parse_col4(color, 1) / 15.0;
+ b = _parse_col4(color, 2) / 15.0;
+ if (alpha) {
+ a = _parse_col4(color, 3) / 15.0;
+ }
+ } else {
+ r = _parse_col8(color, 0) / 255.0;
+ g = _parse_col8(color, 2) / 255.0;
+ b = _parse_col8(color, 4) / 255.0;
+ if (alpha) {
+ a = _parse_col8(color, 6) / 255.0;
+ }
}
+ ERR_FAIL_COND_V_MSG(r < 0, Color(), "Invalid color code: " + p_rgba + ".");
+ ERR_FAIL_COND_V_MSG(g < 0, Color(), "Invalid color code: " + p_rgba + ".");
+ ERR_FAIL_COND_V_MSG(b < 0, Color(), "Invalid color code: " + p_rgba + ".");
+ ERR_FAIL_COND_V_MSG(a < 0, Color(), "Invalid color code: " + p_rgba + ".");
- int from = alpha ? 2 : 0;
-
- int r = _parse_col(color, from + 0);
- ERR_FAIL_COND_V_MSG(r < 0, Color(), "Invalid color code: " + p_color + ".");
- int g = _parse_col(color, from + 2);
- ERR_FAIL_COND_V_MSG(g < 0, Color(), "Invalid color code: " + p_color + ".");
- int b = _parse_col(color, from + 4);
- ERR_FAIL_COND_V_MSG(b < 0, Color(), "Invalid color code: " + p_color + ".");
-
- return Color(r / 255.0, g / 255.0, b / 255.0, a / 255.0);
+ return Color(r, g, b, a);
}
bool Color::html_is_valid(const String &p_color) {
@@ -354,41 +347,22 @@ bool Color::html_is_valid(const String &p_color) {
return false;
}
if (color[0] == '#') {
- color = color.substr(1, color.length() - 1);
+ color = color.substr(1);
}
- bool alpha = false;
-
- if (color.length() == 8) {
- alpha = true;
- } else if (color.length() == 6) {
- alpha = false;
- } else {
+ // Check if the amount of hex digits is valid.
+ int len = color.length();
+ if (!(len == 3 || len == 4 || len == 6 || len == 8)) {
return false;
}
- if (alpha) {
- int a = _parse_col(color, 0);
- if (a < 0) {
+ // Check if each hex digit is valid.
+ for (int i = 0; i < len; i++) {
+ if (_parse_col4(color, i) == -1) {
return false;
}
}
- int from = alpha ? 2 : 0;
-
- int r = _parse_col(color, from + 0);
- if (r < 0) {
- return false;
- }
- int g = _parse_col(color, from + 2);
- if (g < 0) {
- return false;
- }
- int b = _parse_col(color, from + 4);
- if (b < 0) {
- return false;
- }
-
return true;
}
@@ -416,7 +390,7 @@ String _to_hex(float p_val) {
String ret;
for (int i = 0; i < 2; i++) {
- CharType c[2] = { 0, 0 };
+ char32_t c[2] = { 0, 0 };
int lv = v & 0xF;
if (lv < 10) {
c[0] = '0' + lv;
@@ -425,7 +399,7 @@ String _to_hex(float p_val) {
}
v >>= 4;
- String cs = (const CharType *)c;
+ String cs = (const char32_t *)c;
ret = cs + ret;
}
@@ -438,7 +412,7 @@ String Color::to_html(bool p_alpha) const {
txt += _to_hex(g);
txt += _to_hex(b);
if (p_alpha) {
- txt = _to_hex(a) + txt;
+ txt += _to_hex(a);
}
return txt;
}
diff --git a/core/color.h b/core/color.h
index 258965fd16..096e97e9ae 100644
--- a/core/color.h
+++ b/core/color.h
@@ -185,7 +185,7 @@ struct Color {
static Color hex(uint32_t p_hex);
static Color hex64(uint64_t p_hex);
- static Color html(const String &p_color);
+ static Color html(const String &p_rgba);
static bool html_is_valid(const String &p_color);
static Color named(const String &p_name);
String to_html(bool p_alpha = true) const;
diff --git a/core/cowdata.h b/core/cowdata.h
index 82daefb5bd..79676e6d80 100644
--- a/core/cowdata.h
+++ b/core/cowdata.h
@@ -40,6 +40,7 @@
template <class T>
class Vector;
class String;
+class Char16String;
class CharString;
template <class T, class V>
class VMap;
@@ -49,6 +50,7 @@ class CowData {
template <class TV>
friend class Vector;
friend class String;
+ friend class Char16String;
friend class CharString;
template <class TV, class VV>
friend class VMap;
diff --git a/core/hashfuncs.h b/core/hashfuncs.h
index d984f6c524..f4048843fc 100644
--- a/core/hashfuncs.h
+++ b/core/hashfuncs.h
@@ -146,6 +146,8 @@ struct HashMapHasherDefault {
static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return p_int; }
static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return (uint32_t)p_int; }
static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return (uint32_t)p_wchar; }
+ static _FORCE_INLINE_ uint32_t hash(const char16_t p_uchar) { return (uint32_t)p_uchar; }
+ static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return (uint32_t)p_uchar; }
static _FORCE_INLINE_ uint32_t hash(const RID &p_rid) { return hash_one_uint64(p_rid.get_id()); }
static _FORCE_INLINE_ uint32_t hash(const StringName &p_string_name) { return p_string_name.hash(); }
diff --git a/core/input/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt
index 7b5abdd61b..2a3cb23202 100644
--- a/core/input/gamecontrollerdb.txt
+++ b/core/input/gamecontrollerdb.txt
@@ -8,6 +8,7 @@
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,
03000000c82d00000650000000000000,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:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00005106000000000000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000310000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00002028000000000000,8BitDo N30,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,
03000000c82d00008010000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
@@ -35,6 +36,7 @@
03000000c82d00000260000000000000,8BitDo SN30 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:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000261000000000000,8BitDo SN30 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:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000031000000000000,8BitDo Wireless Adapter,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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00003032000000000000,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:Windows,
03000000a00500003232000000000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
030000008f0e00001200000000000000,Acme GA-02,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
@@ -52,6 +54,7 @@
03000000d6200000e557000000000000,Batarang,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,
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,
+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,
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,
03000000bc2000000055000000000000,Betop BFM Gamepad,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,
03000000bc2000006312000000000000,Betop 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,
@@ -83,6 +86,8 @@
03000000120c0000f61c000000000000,Elite,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,
030000008f0e00000f31000000000000,EXEQ,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:b3,y:b2,platform:Windows,
03000000341a00000108000000000000,EXEQ RF USB Gamepad 8206,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
+030000006f0e00008001000000000000,Faceoff Wired Pro Controller for Nintendo Switch,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,
+030000006f0e00008401000000000000,Faceoff Deluxe+ Audio Wired Controller for Nintendo Switch,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,
03000000852100000201000000000000,FF-GP1,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,
030000000d0f00008500000000000000,Fighting Commander 2016 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,
030000000d0f00008400000000000000,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,
@@ -98,8 +103,10 @@
03000000ac0500003d03000000000000,GameSir,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,
03000000ac0500004d04000000000000,GameSir,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,
03000000ffff00000000000000000000,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: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,
030000006f0e00000102000000007801,GameStop Xbox 360 Wired 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:Windows,
030000009b2800003200000000000000,GC/N64 to USB v3.4,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
+030000009b2800006000000000000000,GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
030000008305000009a0000000000000,Genius,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,
030000008305000031b0000000000000,Genius Maxfire Blaze 3,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,
03000000451300000010000000000000,Genius Maxfire Grandias 12,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,
@@ -157,6 +164,7 @@
030000006d04000016c2000000000000,Logitech Dual Action,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,
030000006d04000018c2000000000000,Logitech F510 Gamepad,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,
030000006d04000019c2000000000000,Logitech F710 Gamepad,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,
+030000006d0400001ac2000000000000,Logitech Precision Gamepad,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,lefttrigger:b6,righttrigger:b7,platform:Windows,
03000000380700006652000000000000,Mad Catz C.T.R.L.R,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,
@@ -183,8 +191,11 @@
03000000790000000018000000000000,Mayflash WiiU Pro Game Controller Adapter (DInput),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,
03000000790000002418000000000000,Mega Drive,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b2,start:b9,x:b3,y:b4,platform:Windows,
03000000380700006382000000000000,MLG GamePad 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,
+03000000c62400002a89000000000000,MOGA XP5-A Plus,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:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c62400002b89000000000000,MOGA XP5-A 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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000efbe0000edfe000000000000,Monect Virtual 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:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
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,
+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,
030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Windows,
03000000152000000182000000000000,NGDS,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:Windows,
03000000bd12000015d0000000000000,Nintendo Retrolink USB Super SNES Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,
@@ -197,6 +208,7 @@
030000006b14000001a1000000000000,Orange 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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
03000000362800000100000000000000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows,
03000000120c0000f60e000000000000,P4 Wired Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00000901000000000000,PDP Versus Fighting Pad,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,
030000008f0e00000300000000000000,Piranha xtreme,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,
030000004c050000da0c000000000000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,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,
@@ -232,8 +244,11 @@
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,
03000000321500000204000000000000,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: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,
+03000000321500000810000011010000,Razer Panthera Evo Arcade Stick for PS4,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b13,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,
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,
+03000000321500000011000000000000,Razer Raion Fightpad for 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,
+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,
030000000d0f00001100000000000000,REAL ARCADE PRO.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,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00006a00000000000000,Real Arcade Pro.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:Windows,
030000000d0f00006b00000000000000,Real Arcade Pro.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:a3,start:b9,x:b0,y:b3,platform:Windows,
@@ -248,6 +263,7 @@
0300000000f00000f100000000000000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,
030000006b140000010d000000000000,Revolution Pro 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,
030000006b140000020d000000000000,Revolution Pro Controller 2(1/2),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,
+030000006b140000130d000000000000,Revolution Pro Controller 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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000006f0e00001e01000000000000,Rock Candy 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,
030000006f0e00002801000000000000,Rock Candy 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,
030000006f0e00002f01000000000000,Rock Candy 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,
@@ -275,16 +291,19 @@
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,
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,
03000000381000001814000000000000,SteelSeries Stratus XL,a:b0,b:b1,back:b18,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b19,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b2,y:b3,platform:Windows,
03000000790000001c18000000000000,STK-7024X,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,
03000000ff1100003133000000000000,SVEN X-PAD,a:b2,b:b3,back:b4,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:a4,start:b5,x:b0,y:b1,platform:Windows,
03000000d620000011a7000000000000,Switch,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,
+03000000457500002211000000000000,SZMY-POWER PC 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:Windows,
030000004f04000007d0000000000000,T Mini Wireless,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,
030000004f0400000ab1000000000000,T.16000M,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b10,x:b2,y:b3,platform:Windows,
03000000fa1900000706000000000000,Team 5,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,
03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
030000004f04000015b3000000000000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
030000004f04000023b3000000000000,Thrustmaster Dual Trigger 3-in-1,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,
+030000004f0400000ed0000000000000,ThrustMaster eSwap PRO 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,
030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Windows,
030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
03000000666600000488000000000000,TigerGame PS/PS2 Game Controller Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,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,
@@ -306,6 +325,7 @@
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 Pro Fight Stick for 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,
+030000006f0e00000702000000000000,Victrix Pro Fight Stick for 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: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,
030000005e0400000a0b000000000000,Xbox Adaptive 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:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000341a00000608000000000000,Xeox,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,
@@ -315,28 +335,39 @@
03000000786901006e70000000000000,XInput 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:Windows,
xinput,XInput 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:Windows,
03000000790000004f18000000000000,ZD-T Android,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,
-030000009b2800006000000000000000,GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
+03000000120c0000101e000000000000,ZEROPLUS P4 Wired 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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
# Mac OS X
030000008f0e00000300000009010000,2In1 USB Joystick,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,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,
03000000c82d00000650000001000000,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:Mac OS X,
+03000000c82d00005106000000010000,8BitDo M30 Gamepad,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001590000001000000,8BitDo N30 Pro 2,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: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,
+03000000c82d00006528000000010000,8BitDo N30 Pro 2,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:Mac OS X,
+030000003512000012ab000001000000,8BitDo NES30 Gamepad,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,
03000000022000000090000001000000,8Bitdo NES30 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:Mac OS X,
03000000203800000900000000010000,8Bitdo NES30 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:Mac OS X,
03000000c82d00000190000001000000,8Bitdo NES30 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:Mac OS X,
03000000102800000900000000000000,8Bitdo SFC30 GamePad Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001290000001000000,8BitDo SN30 Gamepad,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000160000001000000,8BitDo SN30 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,
03000000c82d00000161000000010000,8BitDo SN30 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:Mac OS X,
03000000c82d00000260000001000000,8BitDo SN30 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:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000261000000010000,8BitDo SN30 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:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000031000001000000,8BitDo Wireless Adapter,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:Mac OS X,
+03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00003032000000010000,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:a31,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000a00500003232000008010000,8Bitdo Zero GamePad,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:Mac OS X,
03000000a00500003232000009010000,8Bitdo Zero GamePad,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:Mac OS X,
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,
+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,
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,
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,
03000000a306000022f6000001030000,Cyborg V.3 Rumble 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:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000ad1b000001f9000000000000,Gamestop BB-070 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,
030000006f0e00000102000000000000,GameStop Xbox 360 Wired 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,
030000007d0400000540000001010000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
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,
@@ -378,11 +409,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000d8140000cecf000000000000,MC 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,
030000005e0400002700000001010000,Microsoft SideWinder Plug & Play Game Pad,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,leftx:a0,lefty:a1,righttrigger:b5,x:b2,y:b3,platform:Mac OS X,
03000000d62000007162000001000000,Moga Pro 2 HID,a:b0,b:b1,back:b9,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:b6,x:b2,y:b3,platform:Mac OS X,
+03000000c62400002a89000000010000,MOGA XP5-A Plus,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,
+03000000c62400002b89000000010000,MOGA XP5-A 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,
03000000632500007505000000020000,NEOGEO mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X,
030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000d620000011a7000000020000,Nintendo Switch Core (Plus) Wired 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,
030000007e0500000920000000000000,Nintendo Switch Pro 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:Mac OS X,
030000007e0500000920000001000000,Nintendo Switch Pro 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:Mac OS X,
+03000000550900001472000025050000,NVIDIA Controller v01.04,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X,
+030000006f0e00000901000002010000,PDP Versus Fighting Pad,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,
030000008f0e00000300000000000000,Piranha xtreme,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:Mac OS X,
030000004c050000da0c000000010000,Playstation Classic 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:Mac OS X,
03000000d62000006dca000000010000,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:Mac OS X,
@@ -397,12 +432,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
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,
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 Fightpad for 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,
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,
03000000790000001100000000000000,Retrolink Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a3,lefty:a4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
030000006b140000010d000000010000,Revolution Pro 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,
+030000006b140000130d000000010000,Revolution Pro Controller 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: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,
03000000c6240000fefa000000000000,Rock Candy Gamepad for PS3,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,
03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Mac OS X,
03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X,
@@ -418,18 +455,22 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000381000002014000001000000,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,
03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,
03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,
+03000000457500002211000000010000,SZMY-POWER PC 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:Mac OS X,
030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X,
+030000004f0400000ed0000000020000,ThrustMaster eSwap PRO 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,
030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X,
03000000bd12000015d0000000000000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000bd12000015d0000000010000,Tomee SNES USB Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
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,
030000006f0e00000302000025040000,Victrix Pro Fight Stick for 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:Mac OS X,
+030000006f0e00000702000003060000,Victrix Pro Fight Stick for 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:Mac OS X,
03000000791d00000103000009010000,Wii Classic Controller,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,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: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,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,
03000000c6240000045d000000000000,Xbox 360 Wired 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,
030000005e0400000a0b000000000000,Xbox Adaptive 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,
+030000005e040000050b000003090000,Xbox Elite Wireless Controller Series 2,a:b0,b:b1,back:b31,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b53,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:Mac OS X,
030000005e040000d102000000000000,Xbox One Wired 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 Wired 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,
030000005e040000e302000000000000,Xbox One Wired 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,
@@ -439,8 +480,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e040000fd02000003090000,Xbox Wireless 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,
03000000172700004431000029010000,XiaoMi Game 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 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: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,
+03000000120c0000101e000000010000,ZEROPLUS P4 Wired 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: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,
# 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,
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,
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,
@@ -465,8 +508,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000c82d00006228000000010000,8BitDo SN30 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,
03000000c82d00000260000011010000,8BitDo SN30 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,
05000000c82d00000261000000010000,8BitDo SN30 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,
+05000000202800000900000000010000,8BitDo SNES30 Gamepad,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,
030000005e0400008e02000020010000,8BitDo Wireless Adapter,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,
03000000c82d00000031000011010000,8BitDo Wireless Adapter,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,
+03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,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,
05000000a00500003232000001000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
05000000a00500003232000008010000,8Bitdo Zero GamePad,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,
@@ -475,10 +520,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e00003901000000430000,Afterglow Prismatic 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,
030000006f0e00003901000013020000,Afterglow Prismatic Wired Controller 048-007-NA,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,
03000000100000008200000011010000,Akishop Customs PS360+ v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+030000007c1800000006000010010000,Alienware Dual Compatible Game Pad,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:a3,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
05000000491900000204000021000000,Amazon Fire Game 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,
05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,
05000000050b00000045000040000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,
03000000120c00000500000010010000,AxisPad,a:b2,b:b3,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:a2,start:b11,x:b0,y:b1,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,
03000000666600006706000000010000,boom PSX to PC Converter,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:Linux,
03000000ffff0000ffff000000010000,Chinese-made 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,
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,
@@ -513,22 +560,27 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f00006a00000011010000,HORI CO. LTD. Real Arcade Pro.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,
030000000d0f00006b00000011010000,HORI CO. LTD. Real Arcade Pro.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:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00002200000011010000,HORI CO. LTD. REAL ARCADE Pro.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:Linux,
+030000000d0f00008500000010010000,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: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,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,
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,
03000000ad1b000001f5000033050000,Hori Pad EX Turbo 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,
030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro Pad,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:Linux,
+030000000d0f0000aa00000011010000,HORI Real Arcade Pro,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:Linux,
030000000d0f00001600000000010000,Hori Real Arcade Pro.EX-SE (Xbox 360),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,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,
030000000d0f0000ee00000011010000,HORIPAD mini4,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,
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,
030000008f0e00001330000010010000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Linux,
+03000000242e00008816000001010000,Hyperkin X91,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,
03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
050000006964726f69643a636f6e0000,idroid:con,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,
03000000b50700001503000010010000,impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
03000000d80400008200000003000000,IMS PCU#0 Gamepad Interface,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux,
03000000fd0500000030000000010000,InterAct GoPad I-73000 (Fighting Game Layout),a:b3,b:b4,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b7,x:b0,y:b1,platform:Linux,
0500000049190000020400001b010000,Ipega PG-9069 - Bluetooth Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b161,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,
+03000000632500007505000011010000,Ipega PG-9099 - Bluetooth 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:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000006e0500000320000010010000,JC-U3613M - DirectInput Mode,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux,
03000000300f00001001000010010000,Jess Tech Dual Analog Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
03000000300f00000b01000010010000,Jess Tech GGE909 PC Recoil Pad,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:a2,start:b9,x:b3,y:b0,platform:Linux,
@@ -567,7 +619,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000380700003888000010010000,MadCatz PC USB Wired Stick 8838,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,
03000000120c00000500000000010000,Manta Dualshock 2,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:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
-03000000790000004318000010010000,Mayflash GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
+03000000790000004318000010010000,Mayflash GameCube Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
03000000242f00007300000011010000,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:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux,
0300000079000000d218000011010000,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:Linux,
03000000d620000010a7000011010000,Mayflash Magic NS,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,
@@ -588,14 +640,17 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000d6200000e589000001000000,Moga 2 HID,a:b0,b:b1,back:b9,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:b6,x:b2,y:b3,platform:Linux,
05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,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:b6,x:b2,y:b3,platform:Linux,
05000000d62000007162000001000000,Moga Pro 2 HID,a:b0,b:b1,back:b9,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:b6,x:b2,y:b3,platform:Linux,
+03000000c62400002b89000011010000,MOGA XP5-A 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,
+05000000c62400002a89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,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,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: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,
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,
030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Linux,
060000007e0500000820000000000000,Nintendo Combined Joy-Cons (joycond),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
-050000007e0500000920000001800000,Nintendo Switch Pro Controller (joycond),a:b0,b:b1,x:b3,y:b2,back:b9,guide:b11,start:b10,leftstick:b12,rightstick:b13,leftshoulder:b5,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b7,righttrigger:b8,platform:Linux,
-030000007e0500000920000011810000,Nintendo Switch Pro Controller Wired (joycond),a:b0,b:b1,x:b3,y:b2,back:b9,guide:b11,start:b10,leftstick:b12,rightstick:b13,leftshoulder:b5,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b7,righttrigger:b8,platform:Linux,
030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux,
050000007e0500000920000001000000,Nintendo Switch Pro 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:Linux,
+050000007e0500000920000001800000,Nintendo Switch Pro Controller (joycond),a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
+030000007e0500000920000011810000,Nintendo Switch Pro Controller Wired (joycond),a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,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:b3,y:b2,platform:Linux,
05000000010000000100000003000000,Nintendo Wiimote,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,
030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,
@@ -603,19 +658,29 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000550900001472000011010000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,
05000000550900001472000001000000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,
03000000451300000830000010010000,NYKO CORE,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,
+19000000010000000100000001010000,odroidgo2_joypad,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,
+19000000010000000200000011000000,odroidgo2_joypad_v11,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux,
030000005e0400000202000000010000,Old Xbox pad,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,
05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,
05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux,
03000000830500005020000010010000,Padix Co. Ltd. Rockfire PSX/USB Bridge,a:b0,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:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux,
+03000000790000001c18000011010000,PC Game 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,
03000000ff1100003133000010010000,PC Game 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,
+030000006f0e0000b802000001010000,PDP AFTERGLOW Wired Xbox One Controller,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
030000006f0e00006401000001010000,PDP Battlefield 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,
+030000006f0e00008001000011010000,PDP CO. LTD. Faceoff Wired Pro Controller for Nintendo Switch,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,
030000006f0e00003101000000010000,PDP EA Sports 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,
030000006f0e0000c802000012010000,PDP Kingdom Hearts 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,
+030000006f0e00008701000011010000,PDP Rock Candy Wired Controller for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,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,
+030000006f0e00000901000011010000,PDP Versus Fighting Pad,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,
030000006f0e0000a802000023020000,PDP Wired Controller for Xbox One,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,
+030000006f0e00008501000011010000,PDP Wired Fight Pad Pro for Nintendo Switch,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:Linux,
+0500000049190000030400001b010000,PG-9099,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,
030000004c050000da0c000011010000,Playstation 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,
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,
03000000d62000006dca000011010000,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:Linux,
+03000000c62400001a58000001010000,PowerA Xbox One Cabled,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,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,
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,
@@ -640,18 +705,21 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
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,
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,
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,
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,
030000009b2800003200000001010000,Raphnet Technologies GC/N64 to USB v3.4,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 Technologies GC/N64 to USB v3.6,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,
030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,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,
-030000008916000000fd000024010000,Razer Onza Tournament 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,
+030000008916000000fd000024010000,Razer Onza Tournament Edition,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,
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,
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,
+03000000321500000011000011010000,Razer Raion Fightpad for 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,
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,
@@ -662,11 +730,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
0300000081170000990a000001010000,Retronic Adapter,a:b0,leftx:a0,lefty:a1,platform:Linux,
0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,
030000006b140000010d000011010000,Revolution Pro 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,
+030000006b140000130d000011010000,Revolution Pro Controller 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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e00001f01000000010000,Rock Candy,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,
030000006f0e00001e01000011010000,Rock Candy 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,
030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,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,
03000000a306000023f6000011010000,Saitek Cyborg V.1 Game 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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
-03000000a30600001005000000010000,Saitek Saitek P150,platform:Linux,a:b0,b:b1,y:b4,x:b3,leftshoulder:b7,rightshoulder:b2,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,lefttrigger:b6,righttrigger:b5,
03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux,
03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux,
03000000300f00001201000010010000,Saitek P380,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
@@ -674,6 +742,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,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:a2,start:b8,x:b0,y:b3,platform:Linux,
03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
03000000a306000020f6000011010000,Saitek PS2700 Rumble 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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
+03000000a30600001005000000010000,Saitek Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,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,
03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,a:b12,b:b10,back:b4,dpdown:b2,dpleft:b3,dpright:b1,dpup:b0,leftshoulder:b9,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b8,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b5,x:b13,y:b11,platform:Linux,
03000000f025000021c1000010010000,ShanWan Gioteck PS3 Wired 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,
@@ -687,7 +756,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000d11800000094000011010000,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:Linux,
03000000de2800000112000001000000,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:Linux,
03000000de2800000211000001000000,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:Linux,
+03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
03000000de2800004211000001000000,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:Linux,
+03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,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,
05000000de2800000212000001000000,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:Linux,
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:Linux,
@@ -695,9 +766,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000de280000ff11000001000000,Steam Virtual Gamepad,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,
03000000381000003014000075010000,SteelSeries Stratus Duo,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,
03000000381000003114000075010000,SteelSeries Stratus Duo,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,
+0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,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,
05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,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,
03000000ad1b000038f0000090040000,Street Fighter IV FightStick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
-030000003b07000004a1000000010000,Suncom SFX Plus for USB,a:b0,b:b2,x:b1,y:b3,back:b7,start:b8,leftshoulder:b6,rightshoulder:b9,leftx:a0,lefty:a1,lefttrigger:b4,righttrigger:b5,platform:Linux,
+030000003b07000004a1000000010000,Suncom SFX Plus for USB,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:Linux,
03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,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,
0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,
03000000457500002211000010010000,SZMY-POWER CO. LTD. GAMEPAD,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:Linux,
@@ -705,7 +777,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,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,
-03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,x:b3,y:b5,back:b11,start:b1,leftstick:b10,rightstick:b0,leftshoulder:b6,rightshoulder:b8,leftx:a0,lefty:a1,lefttrigger:b7,righttrigger:b9,platform:Linux,
+030000004f0400000ed0000011010000,ThrustMaster eSwap PRO 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,
+03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,back:b11,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b0,righttrigger:b9,start:b1,x:b3,y:b5,platform:Linux,
030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux,
030000004f04000026b3000002040000,Thrustmaster Gamepad GP XID,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,
03000000c6240000025b000002020000,Thrustmaster GPX Gamepad,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,
@@ -722,8 +795,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
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 Gamepad1,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux,
030000006f0e00000302000011010000,Victrix Pro Fight Stick for 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 Fight Stick for 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,
05000000ac0500003232000001000000,VR-BOX,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,
03000000791d00000103000010010000,Wii Classic Controller,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,
+050000000d0f0000f600000001000000,Wireless HORIPAD Switch Pro 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:Linux,
030000005e0400008e02000010010000,X360 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,
030000005e0400008e02000014010000,X360 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,
030000005e0400001907000000010000,X360 Wireless 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,
@@ -735,44 +810,70 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),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,
030000005e040000d102000002010000,Xbox One 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,
050000005e040000fd02000030110000,Xbox One 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,
+050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,
030000005e040000ea02000000000000,Xbox One 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,
050000005e040000e002000003090000,Xbox One Wireless 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:Linux,
050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,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,
030000005e040000ea02000001030000,Xbox One Wireless Controller (Model 1708),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,xbox360 Wireless 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,
03000000450c00002043000010010000,XEOX Gamepad SL-6556-BK,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,
03000000ac0500005b05000010010000,Xiaoji Gamesir-G3w,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:Linux,
05000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux,
03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,
xinput,XInput 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,
03000000120c0000100e000011010000,ZEROPLUS P4 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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
-030000005e0400008e02000000010000,xbox360 Wireless EasySMX,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
-030000009b2800006000000001010000,Raphnet Technologies GC/N64 to USB v3.6,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,
+03000000120c0000101e000011010000,ZEROPLUS P4 Wired 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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
# Android
+05000000c82d000006500000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000051060000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,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,
+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,
+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,
+05000000c82d000012900000ffff3f00,8BitDo SN30 Gamepad,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000062280000ffff3f00,8BitDo SN30 Gamepad,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,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+,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,
+050000002028000009000000ffff3f00,8BitDo SNES30 Gamepad,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 Gamepad,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,
+05000000c82d000018900000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
+05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,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,
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,
+0500000031366332860c44aadfff0f00,GS Gamepad,a:b0,b:b1,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:b2,y:b3,platform:Android,
+0500000083050000602000000ffe0000,iBuffalo SNES Controller,a:b1,b:b0,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b15,rightshoulder:b16,start:b10,x:b3,y:b2,platform:Android,
64633436313965656664373634323364,Microsoft X-Box 360 pad,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,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: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,
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,
050000005509000003720000cf7f3f00,NVIDIA Controller v01.01,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 v01.03,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 v01.04,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,
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,
+030000004c050000cc09000000006800,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,
050000004c050000c4050000fffe3f00,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,
050000004c050000cc090000fffe3f00,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,
+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,
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,
+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,
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,
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,
+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 USB 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,
+30306539356238653637313730656134,Wireless 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,
050000005e040000e00200000ffe3f00,Xbox One Wireless 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,
050000005e040000fd020000ffff3f00,Xbox One Wireless 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:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000005e04000091020000ff073f00,Xbox Wireless 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,
34356136633366613530316338376136,Xbox Wireless 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,
-7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Android,
+050000001727000044310000ffff3f00,XiaoMi Game 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
05000000ac0500000100000000006d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS,
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index 37240f234a..cc8d68be83 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -34,9 +34,9 @@
#include <stdio.h>
-Error PackedData::add_pack(const String &p_path, bool p_replace_files) {
+Error PackedData::add_pack(const String &p_path, bool p_replace_files, size_t p_offset) {
for (int i = 0; i < sources.size(); i++) {
- if (sources[i]->try_open_pack(p_path, p_replace_files)) {
+ if (sources[i]->try_open_pack(p_path, p_replace_files, p_offset)) {
return OK;
}
}
@@ -46,7 +46,7 @@ Error PackedData::add_pack(const String &p_path, bool p_replace_files) {
void PackedData::add_path(const String &pkg_path, const String &path, uint64_t ofs, uint64_t size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files) {
PathMD5 pmd5(path.md5_buffer());
- //printf("adding path %ls, %lli, %lli\n", path.c_str(), pmd5.a, pmd5.b);
+ //printf("adding path %s, %lli, %lli\n", path.utf8().get_data(), pmd5.a, pmd5.b);
bool exists = files.has(pmd5);
@@ -123,15 +123,24 @@ PackedData::~PackedData() {
//////////////////////////////////////////////////////////////////
-bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files) {
+bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset) {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
if (!f) {
return false;
}
+ f->seek(p_offset);
+
uint32_t magic = f->get_32();
if (magic != PACK_HEADER_MAGIC) {
+ // loading with offset feature not supported for self contained exe files
+ if (p_offset != 0) {
+ f->close();
+ memdelete(f);
+ ERR_FAIL_V_MSG(false, "Loading self-contained executable with offset not supported.");
+ }
+
//maybe at the end.... self contained exe
f->seek_end();
f->seek(f->get_position() - 4);
@@ -191,7 +200,7 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files)
uint64_t size = f->get_64();
uint8_t md5[16];
f->get_buffer(md5, 16);
- PackedData::get_singleton()->add_path(p_path, path, ofs, size, md5, this, p_replace_files);
+ PackedData::get_singleton()->add_path(p_path, path, ofs + p_offset, size, md5, this, p_replace_files);
}
f->close();
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index 348bc0c450..6e316119cb 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -108,7 +108,7 @@ public:
_FORCE_INLINE_ bool is_disabled() const { return disabled; }
static PackedData *get_singleton() { return singleton; }
- Error add_pack(const String &p_path, bool p_replace_files);
+ Error add_pack(const String &p_path, bool p_replace_files, size_t p_offset);
_FORCE_INLINE_ FileAccess *try_open_path(const String &p_path);
_FORCE_INLINE_ bool has_path(const String &p_path);
@@ -119,14 +119,14 @@ public:
class PackSource {
public:
- virtual bool try_open_pack(const String &p_path, bool p_replace_files) = 0;
+ virtual bool try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset) = 0;
virtual FileAccess *get_file(const String &p_path, PackedData::PackedFile *p_file) = 0;
virtual ~PackSource() {}
};
class PackedSourcePCK : public PackSource {
public:
- virtual bool try_open_pack(const String &p_path, bool p_replace_files);
+ virtual bool try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset);
virtual FileAccess *get_file(const String &p_path, PackedData::PackedFile *p_file);
};
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index c3a62706c7..d75ca2fdc6 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -147,8 +147,11 @@ unzFile ZipArchive::get_file_handle(String p_file) const {
return pkg;
}
-bool ZipArchive::try_open_pack(const String &p_path, bool p_replace_files) {
- //printf("opening zip pack %ls, %i, %i\n", p_name.c_str(), p_name.extension().nocasecmp_to("zip"), p_name.extension().nocasecmp_to("pcz"));
+bool ZipArchive::try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset = 0) {
+ //printf("opening zip pack %s, %i, %i\n", p_name.utf8().get_data(), p_name.extension().nocasecmp_to("zip"), p_name.extension().nocasecmp_to("pcz"));
+ // load with offset feature only supported for PCK files
+ ERR_FAIL_COND_V_MSG(p_offset != 0, false, "Invalid PCK data. Note that loading files with a non-zero offset isn't supported with ZIP archives.");
+
if (p_path.get_extension().nocasecmp_to("zip") != 0 && p_path.get_extension().nocasecmp_to("pcz") != 0) {
return false;
}
@@ -198,7 +201,7 @@ bool ZipArchive::try_open_pack(const String &p_path, bool p_replace_files) {
uint8_t md5[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
PackedData::get_singleton()->add_path(p_path, fname, 1, 0, md5, this, p_replace_files);
- //printf("packed data add path %ls, %ls\n", p_name.c_str(), fname.c_str());
+ //printf("packed data add path %s, %s\n", p_name.utf8().get_data(), fname.utf8().get_data());
if ((i + 1) < gi.number_entry) {
unzGoToNextFile(zfile);
diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h
index 776e830f36..2cce24e878 100644
--- a/core/io/file_access_zip.h
+++ b/core/io/file_access_zip.h
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef MINIZIP_ENABLED
-
#ifndef FILE_ACCESS_ZIP_H
#define FILE_ACCESS_ZIP_H
+#ifdef MINIZIP_ENABLED
+
#include "core/io/file_access_pack.h"
#include "core/map.h"
@@ -69,7 +69,7 @@ public:
bool file_exists(String p_name) const;
- virtual bool try_open_pack(const String &p_path, bool p_replace_files);
+ virtual bool try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset);
FileAccess *get_file(const String &p_path, PackedData::PackedFile *p_file);
static ZipArchive *get_singleton();
@@ -113,6 +113,6 @@ public:
~FileAccessZip();
};
-#endif // FILE_ACCESS_ZIP_H
-
#endif // MINIZIP_ENABLED
+
+#endif // FILE_ACCESS_ZIP_H
diff --git a/core/io/ip_address.cpp b/core/io/ip_address.cpp
index c7a0ae5605..d0fb63b958 100644
--- a/core/io/ip_address.cpp
+++ b/core/io/ip_address.cpp
@@ -71,7 +71,7 @@ static void _parse_hex(const String &p_string, int p_start, uint8_t *p_dst) {
}
int n = 0;
- CharType c = p_string[i];
+ char32_t c = p_string[i];
if (c >= '0' && c <= '9') {
n = c - '0';
} else if (c >= 'a' && c <= 'f') {
@@ -101,7 +101,7 @@ void IP_Address::_parse_ipv6(const String &p_string) {
int parts_idx = 0;
for (int i = 0; i < p_string.length(); i++) {
- CharType c = p_string[i];
+ char32_t c = p_string[i];
if (c == ':') {
if (i == 0) {
continue; // next must be a ":"
diff --git a/core/io/json.cpp b/core/io/json.cpp
index 8bdd6385cb..1b89d966fd 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -125,7 +125,7 @@ String JSON::print(const Variant &p_var, const String &p_indent, bool p_sort_key
return _print_var(p_var, p_indent, 0, p_sort_keys);
}
-Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str) {
+Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str) {
while (p_len > 0) {
switch (p_str[index]) {
case '\n': {
@@ -180,12 +180,12 @@ Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_to
} else if (p_str[index] == '\\') {
//escaped characters...
index++;
- CharType next = p_str[index];
+ char32_t next = p_str[index];
if (next == 0) {
r_err_str = "Unterminated String";
return ERR_PARSE_ERROR;
}
- CharType res = 0;
+ char32_t res = 0;
switch (next) {
case 'b':
@@ -206,7 +206,7 @@ Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_to
case 'u': {
// hex number
for (int j = 0; j < 4; j++) {
- CharType c = p_str[index + j + 1];
+ char32_t c = p_str[index + j + 1];
if (c == 0) {
r_err_str = "Unterminated String";
return ERR_PARSE_ERROR;
@@ -215,7 +215,7 @@ Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_to
r_err_str = "Malformed hex constant in string";
return ERR_PARSE_ERROR;
}
- CharType v;
+ char32_t v;
if (c >= '0' && c <= '9') {
v = c - '0';
} else if (c >= 'a' && c <= 'f') {
@@ -264,7 +264,7 @@ Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_to
if (p_str[index] == '-' || (p_str[index] >= '0' && p_str[index] <= '9')) {
//a number
- const CharType *rptr;
+ const char32_t *rptr;
double number = String::to_float(&p_str[index], &rptr);
index += (rptr - &p_str[index]);
r_token.type = TK_NUMBER;
@@ -293,7 +293,7 @@ Error JSON::_get_token(const CharType *p_str, int &index, int p_len, Token &r_to
return ERR_PARSE_ERROR;
}
-Error JSON::_parse_value(Variant &value, Token &token, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str) {
+Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
if (token.type == TK_CURLY_BRACKET_OPEN) {
Dictionary d;
Error err = _parse_object(d, p_str, index, p_len, line, r_err_str);
@@ -337,7 +337,7 @@ Error JSON::_parse_value(Variant &value, Token &token, const CharType *p_str, in
}
}
-Error JSON::_parse_array(Array &array, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str) {
+Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
Token token;
bool need_comma = false;
@@ -375,7 +375,7 @@ Error JSON::_parse_array(Array &array, const CharType *p_str, int &index, int p_
return ERR_PARSE_ERROR;
}
-Error JSON::_parse_object(Dictionary &object, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str) {
+Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
bool at_key = true;
String key;
Token token;
@@ -439,7 +439,7 @@ Error JSON::_parse_object(Dictionary &object, const CharType *p_str, int &index,
}
Error JSON::parse(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line) {
- const CharType *str = p_json.ptr();
+ const char32_t *str = p_json.ptr();
int idx = 0;
int len = p_json.length();
Token token;
diff --git a/core/io/json.h b/core/io/json.h
index 4fc5630a93..9122228163 100644
--- a/core/io/json.h
+++ b/core/io/json.h
@@ -65,10 +65,10 @@ class JSON {
static String _print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys);
- static Error _get_token(const CharType *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str);
- static Error _parse_value(Variant &value, Token &token, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str);
- static Error _parse_array(Array &array, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str);
- static Error _parse_object(Dictionary &object, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str);
+ static Error _get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str);
+ static Error _parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
+ static Error _parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
+ static Error _parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
public:
static String print(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true);
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index 534f3e44de..b5c598e860 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -195,7 +195,8 @@ RES ResourceLoader::_load(const String &p_path, const String &p_original_path, c
return res;
}
- ERR_FAIL_COND_V_MSG(found, RES(), "Failed loading resource: " + p_path + ".");
+ ERR_FAIL_COND_V_MSG(found, RES(),
+ 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
FileAccessRef file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
@@ -999,6 +1000,9 @@ void ResourceLoader::load_translation_remaps() {
void ResourceLoader::clear_translation_remaps() {
translation_remaps.clear();
+ while (remapped_list.first() != nullptr) {
+ remapped_list.remove(remapped_list.first());
+ }
}
void ResourceLoader::load_path_remaps() {
diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp
index b11267b60f..fc75ac7d1e 100644
--- a/core/io/xml_parser.cpp
+++ b/core/io/xml_parser.cpp
@@ -36,7 +36,7 @@
VARIANT_ENUM_CAST(XMLParser::NodeType);
-static bool _equalsn(const CharType *str1, const CharType *str2, int len) {
+static bool _equalsn(const char32_t *str1, const char32_t *str2, int len) {
int i;
for (i = 0; i < len && str1[i] && str2[i]; ++i) {
if (str1[i] != str2[i]) {
@@ -64,7 +64,7 @@ String XMLParser::_replace_special_characters(const String &origstr) {
int specialChar = -1;
for (int i = 0; i < (int)special_characters.size(); ++i) {
- const CharType *p = &origstr[pos] + 1;
+ const char32_t *p = &origstr[pos] + 1;
if (_equalsn(&special_characters[i][1], p, special_characters[i].length() - 1)) {
specialChar = i;
diff --git a/core/math/audio_frame.h b/core/math/audio_frame.h
index 91f533eafb..43d4a63cd3 100644
--- a/core/math/audio_frame.h
+++ b/core/math/audio_frame.h
@@ -121,7 +121,7 @@ struct AudioFrame {
r = p_frame.r;
}
- _ALWAYS_INLINE_ AudioFrame operator=(const AudioFrame &p_frame) {
+ _ALWAYS_INLINE_ AudioFrame &operator=(const AudioFrame &p_frame) {
l = p_frame.l;
r = p_frame.r;
return *this;
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index 735a30f6cc..1040f9e0e4 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -596,7 +596,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
} break;
case TEXT_CHAR: {
- CharType result[2] = { *p_inputs[0], 0 };
+ char32_t result[2] = { *p_inputs[0], 0 };
*r_return = String(result);
@@ -739,7 +739,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
////////
-static bool _is_number(CharType c) {
+static bool _is_number(char32_t c) {
return (c >= '0' && c <= '9');
}
@@ -747,7 +747,7 @@ Error Expression::_get_token(Token &r_token) {
while (true) {
#define GET_CHAR() (str_ofs >= expression.length() ? 0 : expression[str_ofs++])
- CharType cchar = GET_CHAR();
+ char32_t cchar = GET_CHAR();
switch (cchar) {
case 0: {
@@ -900,7 +900,7 @@ Error Expression::_get_token(Token &r_token) {
case '"': {
String str;
while (true) {
- CharType ch = GET_CHAR();
+ char32_t ch = GET_CHAR();
if (ch == 0) {
_set_error("Unterminated String");
@@ -912,13 +912,13 @@ Error Expression::_get_token(Token &r_token) {
} else if (ch == '\\') {
//escaped characters...
- CharType next = GET_CHAR();
+ char32_t next = GET_CHAR();
if (next == 0) {
_set_error("Unterminated String");
r_token.type = TK_ERROR;
return ERR_PARSE_ERROR;
}
- CharType res = 0;
+ char32_t res = 0;
switch (next) {
case 'b':
@@ -939,7 +939,7 @@ Error Expression::_get_token(Token &r_token) {
case 'u': {
// hex number
for (int j = 0; j < 4; j++) {
- CharType c = GET_CHAR();
+ char32_t c = GET_CHAR();
if (c == 0) {
_set_error("Unterminated String");
@@ -951,7 +951,7 @@ Error Expression::_get_token(Token &r_token) {
r_token.type = TK_ERROR;
return ERR_PARSE_ERROR;
}
- CharType v;
+ char32_t v;
if (_is_number(c)) {
v = c - '0';
} else if (c >= 'a' && c <= 'f') {
@@ -992,7 +992,7 @@ Error Expression::_get_token(Token &r_token) {
break;
}
- CharType next_char = (str_ofs >= expression.length()) ? 0 : expression[str_ofs];
+ char32_t next_char = (str_ofs >= expression.length()) ? 0 : expression[str_ofs];
if (_is_number(cchar) || (cchar == '.' && _is_number(next_char))) {
//a number
@@ -1004,7 +1004,7 @@ Error Expression::_get_token(Token &r_token) {
#define READING_DONE 4
int reading = READING_INT;
- CharType c = cchar;
+ char32_t c = cchar;
bool exp_sign = false;
bool exp_beg = false;
bool is_float = false;
diff --git a/core/math/expression.h b/core/math/expression.h
index 59a9a2f4ed..f2cfe6b1a6 100644
--- a/core/math/expression.h
+++ b/core/math/expression.h
@@ -343,7 +343,7 @@ protected:
public:
Error parse(const String &p_expression, const Vector<String> &p_input_names = Vector<String>());
- Variant execute(Array p_inputs, Object *p_base = nullptr, bool p_show_error = true);
+ Variant execute(Array p_inputs = Array(), Object *p_base = nullptr, bool p_show_error = true);
bool has_execute_failed() const;
String get_error_text() const;
diff --git a/core/math/quat.h b/core/math/quat.h
index 64d0f00912..8619ea3c5c 100644
--- a/core/math/quat.h
+++ b/core/math/quat.h
@@ -130,7 +130,7 @@ public:
w(q.w) {
}
- Quat operator=(const Quat &q) {
+ Quat &operator=(const Quat &q) {
x = q.x;
y = q.y;
z = q.z;
diff --git a/core/method_bind.h b/core/method_bind.h
index ff2c771f81..942e2e0036 100644
--- a/core/method_bind.h
+++ b/core/method_bind.h
@@ -181,18 +181,18 @@ VARIANT_ENUM_CAST(Variant::Type);
VARIANT_ENUM_CAST(Variant::Operator);
template <>
-struct VariantCaster<wchar_t> {
- static _FORCE_INLINE_ wchar_t cast(const Variant &p_variant) {
- return (wchar_t)p_variant.operator int();
+struct VariantCaster<char32_t> {
+ static _FORCE_INLINE_ char32_t cast(const Variant &p_variant) {
+ return (char32_t)p_variant.operator int();
}
};
#ifdef PTRCALL_ENABLED
template <>
-struct PtrToArg<wchar_t> {
- _FORCE_INLINE_ static wchar_t convert(const void *p_ptr) {
- return wchar_t(*reinterpret_cast<const int *>(p_ptr));
+struct PtrToArg<char32_t> {
+ _FORCE_INLINE_ static char32_t convert(const void *p_ptr) {
+ return char32_t(*reinterpret_cast<const int *>(p_ptr));
}
- _FORCE_INLINE_ static void encode(wchar_t p_val, const void *p_ptr) {
+ _FORCE_INLINE_ static void encode(char32_t p_val, const void *p_ptr) {
*(int *)p_ptr = p_val;
}
};
diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp
index 20b3435911..9dbb2952f7 100644
--- a/core/os/file_access.cpp
+++ b/core/os/file_access.cpp
@@ -234,7 +234,7 @@ double FileAccess::get_double() const {
String FileAccess::get_token() const {
CharString token;
- CharType c = get_8();
+ char32_t c = get_8();
while (!eof_reached()) {
if (c <= ' ') {
@@ -299,7 +299,7 @@ public:
String FileAccess::get_line() const {
CharBuffer line;
- CharType c = get_8();
+ char32_t c = get_8();
while (!eof_reached()) {
if (c == '\n' || c == '\0') {
@@ -342,8 +342,8 @@ Vector<String> FileAccess::get_csv_line(const String &p_delim) const {
bool in_quote = false;
String current;
for (int i = 0; i < l.length(); i++) {
- CharType c = l[i];
- CharType s[2] = { 0, 0 };
+ char32_t c = l[i];
+ char32_t s[2] = { 0, 0 };
if (!in_quote && c == p_delim[0]) {
strings.push_back(current);
diff --git a/core/os/os.h b/core/os/os.h
index 48dae99188..8e5c0c26e0 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -86,11 +86,13 @@ public:
protected:
friend class Main;
+ // Needed by tests to setup command-line args.
+ friend int test_main(int argc, char *argv[]);
HasServerFeatureCallback has_server_feature_callback = nullptr;
RenderThreadMode _render_thread_mode = RENDER_THREAD_SAFE;
- // functions used by main to initialize/deinitialize the OS
+ // Functions used by Main to initialize/deinitialize the OS.
void add_logger(Logger *p_logger);
virtual void initialize() = 0;
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index 960a0ec1b0..efe13e740d 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -291,12 +291,12 @@ void ProjectSettings::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-bool ProjectSettings::_load_resource_pack(const String &p_pack, bool p_replace_files) {
+bool ProjectSettings::_load_resource_pack(const String &p_pack, bool p_replace_files, int p_offset) {
if (PackedData::get_singleton()->is_disabled()) {
return false;
}
- bool ok = PackedData::get_singleton()->add_pack(p_pack, p_replace_files) == OK;
+ bool ok = PackedData::get_singleton()->add_pack(p_pack, p_replace_files, p_offset) == OK;
if (!ok) {
return false;
@@ -1030,7 +1030,7 @@ void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("localize_path", "path"), &ProjectSettings::localize_path);
ClassDB::bind_method(D_METHOD("globalize_path", "path"), &ProjectSettings::globalize_path);
ClassDB::bind_method(D_METHOD("save"), &ProjectSettings::save);
- ClassDB::bind_method(D_METHOD("load_resource_pack", "pack", "replace_files"), &ProjectSettings::_load_resource_pack, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("load_resource_pack", "pack", "replace_files", "offset"), &ProjectSettings::_load_resource_pack, DEFVAL(true), DEFVAL(0));
ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &ProjectSettings::property_can_revert);
ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &ProjectSettings::property_get_revert);
diff --git a/core/project_settings.h b/core/project_settings.h
index 70b54ec854..29b2406dd2 100644
--- a/core/project_settings.h
+++ b/core/project_settings.h
@@ -107,7 +107,7 @@ protected:
void _convert_to_last_version(int p_from_version);
- bool _load_resource_pack(const String &p_pack, bool p_replace_files = true);
+ bool _load_resource_pack(const String &p_pack, bool p_replace_files = true, int p_offset = 0);
void _add_property_info_bind(const Dictionary &p_info);
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 5dac42cacb..4f094dd6c6 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -86,6 +86,7 @@ static _Engine *_engine = nullptr;
static _ClassDB *_classdb = nullptr;
static _Marshalls *_marshalls = nullptr;
static _JSON *_json = nullptr;
+static _EngineDebugger *_engine_debugger = nullptr;
static IP *ip = nullptr;
@@ -227,6 +228,7 @@ void register_core_types() {
_classdb = memnew(_ClassDB);
_marshalls = memnew(_Marshalls);
_json = memnew(_JSON);
+ _engine_debugger = memnew(_EngineDebugger);
}
void register_core_settings() {
@@ -256,6 +258,7 @@ void register_core_singletons() {
ClassDB::register_class<InputMap>();
ClassDB::register_class<_JSON>();
ClassDB::register_class<Expression>();
+ ClassDB::register_class<_EngineDebugger>();
Engine::get_singleton()->add_singleton(Engine::Singleton("ProjectSettings", ProjectSettings::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("IP", IP::get_singleton()));
@@ -271,6 +274,7 @@ void register_core_singletons() {
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("JSON", _JSON::get_singleton()));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("EngineDebugger", _EngineDebugger::get_singleton()));
}
void unregister_core_types() {
@@ -281,6 +285,7 @@ void unregister_core_types() {
memdelete(_classdb);
memdelete(_marshalls);
memdelete(_json);
+ memdelete(_engine_debugger);
memdelete(_geometry_2d);
memdelete(_geometry_3d);
diff --git a/core/string_buffer.h b/core/string_buffer.h
index f9cf31075a..a685720851 100644
--- a/core/string_buffer.h
+++ b/core/string_buffer.h
@@ -35,21 +35,21 @@
template <int SHORT_BUFFER_SIZE = 64>
class StringBuffer {
- CharType short_buffer[SHORT_BUFFER_SIZE];
+ char32_t short_buffer[SHORT_BUFFER_SIZE];
String buffer;
int string_length = 0;
- _FORCE_INLINE_ CharType *current_buffer_ptr() {
+ _FORCE_INLINE_ char32_t *current_buffer_ptr() {
return static_cast<String &>(buffer).empty() ? short_buffer : buffer.ptrw();
}
public:
- StringBuffer &append(CharType p_char);
+ StringBuffer &append(char32_t p_char);
StringBuffer &append(const String &p_string);
StringBuffer &append(const char *p_str);
- StringBuffer &append(const CharType *p_str, int p_clip_to_len = -1);
+ StringBuffer &append(const char32_t *p_str, int p_clip_to_len = -1);
- _FORCE_INLINE_ void operator+=(CharType p_char) {
+ _FORCE_INLINE_ void operator+=(char32_t p_char) {
append(p_char);
}
@@ -61,7 +61,7 @@ public:
append(p_str);
}
- _FORCE_INLINE_ void operator+=(const CharType *p_str) {
+ _FORCE_INLINE_ void operator+=(const char32_t *p_str) {
append(p_str);
}
@@ -80,7 +80,7 @@ public:
};
template <int SHORT_BUFFER_SIZE>
-StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(CharType p_char) {
+StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(char32_t p_char) {
reserve(string_length + 2);
current_buffer_ptr()[string_length++] = p_char;
return *this;
@@ -88,7 +88,7 @@ StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(CharTyp
template <int SHORT_BUFFER_SIZE>
StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const String &p_string) {
- return append(p_string.c_str());
+ return append(p_string.get_data());
}
template <int SHORT_BUFFER_SIZE>
@@ -96,7 +96,7 @@ StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const c
int len = strlen(p_str);
reserve(string_length + len + 1);
- CharType *buf = current_buffer_ptr();
+ char32_t *buf = current_buffer_ptr();
for (const char *c_ptr = p_str; *c_ptr; ++c_ptr) {
buf[string_length++] = *c_ptr;
}
@@ -104,13 +104,13 @@ StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const c
}
template <int SHORT_BUFFER_SIZE>
-StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const CharType *p_str, int p_clip_to_len) {
+StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::append(const char32_t *p_str, int p_clip_to_len) {
int len = 0;
while ((p_clip_to_len < 0 || len < p_clip_to_len) && p_str[len]) {
++len;
}
reserve(string_length + len + 1);
- memcpy(&(current_buffer_ptr()[string_length]), p_str, len * sizeof(CharType));
+ memcpy(&(current_buffer_ptr()[string_length]), p_str, len * sizeof(char32_t));
string_length += len;
return *this;
@@ -125,7 +125,7 @@ StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::reserve(int p_
bool need_copy = string_length > 0 && buffer.empty();
buffer.resize(next_power_of_2(p_size));
if (need_copy) {
- memcpy(buffer.ptrw(), short_buffer, string_length * sizeof(CharType));
+ memcpy(buffer.ptrw(), short_buffer, string_length * sizeof(char32_t));
}
return *this;
diff --git a/core/string_builder.cpp b/core/string_builder.cpp
index c8d6498f27..dec299ffa3 100644
--- a/core/string_builder.cpp
+++ b/core/string_builder.cpp
@@ -61,7 +61,7 @@ String StringBuilder::as_string() const {
return "";
}
- CharType *buffer = memnew_arr(CharType, string_length);
+ char32_t *buffer = memnew_arr(char32_t, string_length);
int current_position = 0;
@@ -73,7 +73,7 @@ String StringBuilder::as_string() const {
// Godot string
const String &s = strings[godot_string_elem];
- memcpy(buffer + current_position, s.ptr(), s.length() * sizeof(CharType));
+ memcpy(buffer + current_position, s.ptr(), s.length() * sizeof(char32_t));
current_position += s.length();
diff --git a/core/string_name.cpp b/core/string_name.cpp
index cbf6009681..6260e3ce8c 100644
--- a/core/string_name.cpp
+++ b/core/string_name.cpp
@@ -317,7 +317,7 @@ StringName StringName::search(const char *p_name) {
return StringName(); //does not exist
}
-StringName StringName::search(const CharType *p_name) {
+StringName StringName::search(const char32_t *p_name) {
ERR_FAIL_COND_V(!configured, StringName());
ERR_FAIL_COND_V(!p_name, StringName());
diff --git a/core/string_name.h b/core/string_name.h
index 886ddd0ee7..4f90479bda 100644
--- a/core/string_name.h
+++ b/core/string_name.h
@@ -122,7 +122,7 @@ public:
}
static StringName search(const char *p_name);
- static StringName search(const CharType *p_name);
+ static StringName search(const char32_t *p_name);
static StringName search(const String &p_name);
struct AlphCompare {
diff --git a/core/type_info.h b/core/type_info.h
index e3d2b5bd53..3c7f59bb84 100644
--- a/core/type_info.h
+++ b/core/type_info.h
@@ -132,7 +132,8 @@ MAKE_TYPE_INFO_WITH_META(uint32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_
MAKE_TYPE_INFO_WITH_META(int32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT32)
MAKE_TYPE_INFO_WITH_META(uint64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT64)
MAKE_TYPE_INFO_WITH_META(int64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT64)
-MAKE_TYPE_INFO(wchar_t, Variant::INT)
+MAKE_TYPE_INFO(char16_t, Variant::INT)
+MAKE_TYPE_INFO(char32_t, Variant::INT)
MAKE_TYPE_INFO_WITH_META(float, Variant::FLOAT, GodotTypeInfo::METADATA_REAL_IS_FLOAT)
MAKE_TYPE_INFO_WITH_META(double, Variant::FLOAT, GodotTypeInfo::METADATA_REAL_IS_DOUBLE)
diff --git a/core/ustring.cpp b/core/ustring.cpp
index 9d2d938eaf..d5afbc2b47 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -39,7 +39,6 @@
#include "core/ucaps.h"
#include "core/variant.h"
-#include <wchar.h>
#include <cstdint>
#ifndef NO_USE_STDLIB
@@ -62,9 +61,10 @@
#define IS_HEX_DIGIT(m_d) (((m_d) >= '0' && (m_d) <= '9') || ((m_d) >= 'a' && (m_d) <= 'f') || ((m_d) >= 'A' && (m_d) <= 'F'))
const char CharString::_null = 0;
-const CharType String::_null = 0;
+const char16_t Char16String::_null = 0;
+const char32_t String::_null = 0;
-bool is_symbol(CharType c) {
+bool is_symbol(char32_t c) {
return c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t' || c == ' ');
}
@@ -96,9 +96,11 @@ bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end) {
}
}
-/** STRING **/
+/*************************************************************************/
+/* Char16String */
+/*************************************************************************/
-bool CharString::operator<(const CharString &p_right) const {
+bool Char16String::operator<(const Char16String &p_right) const {
if (length() == 0) {
return p_right.length() != 0;
}
@@ -106,7 +108,7 @@ bool CharString::operator<(const CharString &p_right) const {
return is_str_less(get_data(), p_right.get_data());
}
-CharString &CharString::operator+=(char p_char) {
+Char16String &Char16String::operator+=(char16_t p_char) {
resize(size() ? size() + 1 : 2);
set(length(), 0);
set(length() - 1, p_char);
@@ -114,19 +116,75 @@ CharString &CharString::operator+=(char p_char) {
return *this;
}
-const char *CharString::get_data() const {
+Char16String &Char16String::operator=(const char16_t *p_cstr) {
+ copy_from(p_cstr);
+ return *this;
+}
+
+const char16_t *Char16String::get_data() const {
if (size()) {
return &operator[](0);
} else {
- return "";
+ return u"";
}
}
+void Char16String::copy_from(const char16_t *p_cstr) {
+ if (!p_cstr) {
+ resize(0);
+ return;
+ }
+
+ const char16_t *s = p_cstr;
+ for (; *s; s++) {
+ }
+ size_t len = s - p_cstr;
+
+ if (len == 0) {
+ resize(0);
+ return;
+ }
+
+ Error err = resize(++len); // include terminating null char
+
+ ERR_FAIL_COND_MSG(err != OK, "Failed to copy char16_t string.");
+
+ memcpy(ptrw(), p_cstr, len * sizeof(char16_t));
+}
+
+/*************************************************************************/
+/* CharString */
+/*************************************************************************/
+
+bool CharString::operator<(const CharString &p_right) const {
+ if (length() == 0) {
+ return p_right.length() != 0;
+ }
+
+ return is_str_less(get_data(), p_right.get_data());
+}
+
+CharString &CharString::operator+=(char p_char) {
+ resize(size() ? size() + 1 : 2);
+ set(length(), 0);
+ set(length() - 1, p_char);
+
+ return *this;
+}
+
CharString &CharString::operator=(const char *p_cstr) {
copy_from(p_cstr);
return *this;
}
+const char *CharString::get_data() const {
+ if (size()) {
+ return &operator[](0);
+ } else {
+ return "";
+ }
+}
+
void CharString::copy_from(const char *p_cstr) {
if (!p_cstr) {
resize(0);
@@ -147,7 +205,44 @@ void CharString::copy_from(const char *p_cstr) {
memcpy(ptrw(), p_cstr, len);
}
+/*************************************************************************/
+/* String */
+/*************************************************************************/
+
+//TODO: move to TextServer
+//kind of poor should be rewritten properly
+String String::word_wrap(int p_chars_per_line) const {
+ int from = 0;
+ int last_space = 0;
+ String ret;
+ for (int i = 0; i < length(); i++) {
+ if (i - from >= p_chars_per_line) {
+ if (last_space == -1) {
+ ret += substr(from, i - from + 1) + "\n";
+ } else {
+ ret += substr(from, last_space - from) + "\n";
+ i = last_space; //rewind
+ }
+ from = i + 1;
+ last_space = -1;
+ } else if (operator[](i) == ' ' || operator[](i) == '\t') {
+ last_space = i;
+ } else if (operator[](i) == '\n') {
+ ret += substr(from, i - from) + "\n";
+ from = i + 1;
+ last_space = -1;
+ }
+ }
+
+ if (from < length()) {
+ ret += substr(from, length());
+ }
+
+ return ret;
+}
+
void String::copy_from(const char *p_cstr) {
+ // copy Latin-1 encoded c-string directly
if (!p_cstr) {
resize(0);
return;
@@ -166,21 +261,22 @@ void String::copy_from(const char *p_cstr) {
resize(len + 1); // include 0
- CharType *dst = this->ptrw();
+ char32_t *dst = this->ptrw();
for (int i = 0; i < len + 1; i++) {
dst[i] = p_cstr[i];
}
}
-void String::copy_from(const CharType *p_cstr, const int p_clip_to) {
+void String::copy_from(const char *p_cstr, const int p_clip_to) {
+ // copy Latin-1 encoded c-string directly
if (!p_cstr) {
resize(0);
return;
}
int len = 0;
- const CharType *ptr = p_cstr;
+ const char *ptr = p_cstr;
while ((p_clip_to < 0 || len < p_clip_to) && *(ptr++) != 0) {
len++;
}
@@ -190,55 +286,117 @@ void String::copy_from(const CharType *p_cstr, const int p_clip_to) {
return;
}
- copy_from_unchecked(p_cstr, len);
-}
-
-// assumes the following have already been validated:
-// p_char != nullptr
-// p_length > 0
-// p_length <= p_char strlen
-void String::copy_from_unchecked(const CharType *p_char, const int p_length) {
- resize(p_length + 1);
- set(p_length, 0);
+ resize(len + 1); // include 0
- CharType *dst = ptrw();
+ char32_t *dst = this->ptrw();
- for (int i = 0; i < p_length; i++) {
- dst[i] = p_char[i];
+ for (int i = 0; i < len; i++) {
+ dst[i] = p_cstr[i];
}
+ dst[len] = 0;
}
-void String::copy_from(const CharType &p_char) {
+void String::copy_from(const wchar_t *p_cstr) {
+#ifdef WINDOWS_ENABLED
+ // wchar_t is 16-bit, parse as UTF-16
+ parse_utf16((const char16_t *)p_cstr);
+#else
+ // wchar_t is 32-bit, copy directly
+ copy_from((const char32_t *)p_cstr);
+#endif
+}
+
+void String::copy_from(const wchar_t *p_cstr, const int p_clip_to) {
+#ifdef WINDOWS_ENABLED
+ // wchar_t is 16-bit, parse as UTF-16
+ parse_utf16((const char16_t *)p_cstr, p_clip_to);
+#else
+ // wchar_t is 32-bit, copy directly
+ copy_from((const char32_t *)p_cstr, p_clip_to);
+#endif
+}
+
+void String::copy_from(const char32_t &p_char) {
resize(2);
- set(0, p_char);
+ if ((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff)) {
+ print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(p_char, 16) + ".");
+ set(0, 0xfffd);
+ } else {
+ set(0, p_char);
+ }
set(1, 0);
}
-bool String::operator==(const String &p_str) const {
- if (length() != p_str.length()) {
- return false;
+void String::copy_from(const char32_t *p_cstr) {
+ if (!p_cstr) {
+ resize(0);
+ return;
}
- if (empty()) {
- return true;
+
+ int len = 0;
+ const char32_t *ptr = p_cstr;
+ while (*(ptr++) != 0) {
+ len++;
}
- int l = length();
+ if (len == 0) {
+ resize(0);
+ return;
+ }
- const CharType *src = c_str();
- const CharType *dst = p_str.c_str();
+ copy_from_unchecked(p_cstr, len);
+}
- /* Compare char by char */
- for (int i = 0; i < l; i++) {
- if (src[i] != dst[i]) {
- return false;
+void String::copy_from(const char32_t *p_cstr, const int p_clip_to) {
+ if (!p_cstr) {
+ resize(0);
+ return;
+ }
+
+ int len = 0;
+ const char32_t *ptr = p_cstr;
+ while ((p_clip_to < 0 || len < p_clip_to) && *(ptr++) != 0) {
+ len++;
+ }
+
+ if (len == 0) {
+ resize(0);
+ return;
+ }
+
+ copy_from_unchecked(p_cstr, len);
+}
+
+// assumes the following have already been validated:
+// p_char != nullptr
+// p_length > 0
+// p_length <= p_char strlen
+void String::copy_from_unchecked(const char32_t *p_char, const int p_length) {
+ resize(p_length + 1);
+ set(p_length, 0);
+
+ char32_t *dst = ptrw();
+
+ for (int i = 0; i < p_length; i++) {
+ if ((p_char[i] >= 0xd800 && p_char[i] <= 0xdfff) || (p_char[i] > 0x10ffff)) {
+ print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(p_char[i], 16) + ".");
+ dst[i] = 0xfffd;
+ } else {
+ dst[i] = p_char[i];
}
}
+}
- return true;
+void String::operator=(const char *p_str) {
+ copy_from(p_str);
}
-bool String::operator!=(const String &p_str) const {
- return !(*this == p_str);
+void String::operator=(const char32_t *p_str) {
+ copy_from(p_str);
+}
+
+void String::operator=(const wchar_t *p_str) {
+ copy_from(p_str);
}
String String::operator+(const String &p_str) const {
@@ -247,6 +405,28 @@ String String::operator+(const String &p_str) const {
return res;
}
+String operator+(const char *p_chr, const String &p_str) {
+ String tmp = p_chr;
+ tmp += p_str;
+ return tmp;
+}
+
+String operator+(const wchar_t *p_chr, const String &p_str) {
+#ifdef WINDOWS_ENABLED
+ // wchar_t is 16-bit
+ String tmp = String::utf16((const char16_t *)p_chr);
+#else
+ // wchar_t is 32-bi
+ String tmp = (const char32_t *)p_chr;
+#endif
+ tmp += p_str;
+ return tmp;
+}
+
+String operator+(char32_t p_chr, const String &p_str) {
+ return (String::chr(p_chr) + p_str);
+}
+
String &String::operator+=(const String &p_str) {
if (empty()) {
*this = p_str;
@@ -261,8 +441,8 @@ String &String::operator+=(const String &p_str) {
resize(length() + p_str.size());
- const CharType *src = p_str.c_str();
- CharType *dst = ptrw();
+ const char32_t *src = p_str.get_data();
+ char32_t *dst = ptrw();
set(length(), 0);
@@ -273,19 +453,6 @@ String &String::operator+=(const String &p_str) {
return *this;
}
-String &String::operator+=(const CharType *p_str) {
- *this += String(p_str);
- return *this;
-}
-
-String &String::operator+=(CharType p_char) {
- resize(size() ? size() + 1 : 2);
- set(length(), 0);
- set(length() - 1, p_char);
-
- return *this;
-}
-
String &String::operator+=(const char *p_str) {
if (!p_str || p_str[0] == 0) {
return *this;
@@ -301,7 +468,7 @@ String &String::operator+=(const char *p_str) {
resize(from + src_len + 1);
- CharType *dst = ptrw();
+ char32_t *dst = ptrw();
set(length(), 0);
@@ -312,16 +479,43 @@ String &String::operator+=(const char *p_str) {
return *this;
}
-void String::operator=(const char *p_str) {
- copy_from(p_str);
+String &String::operator+=(const wchar_t *p_str) {
+#ifdef WINDOWS_ENABLED
+ // wchar_t is 16-bit
+ *this += String::utf16((const char16_t *)p_str);
+#else
+ // wchar_t is 32-bit
+ *this += String((const char32_t *)p_str);
+#endif
+ return *this;
}
-void String::operator=(const CharType *p_str) {
- copy_from(p_str);
+String &String::operator+=(const char32_t *p_str) {
+ *this += String(p_str);
+ return *this;
}
-bool String::operator==(const StrRange &p_str_range) const {
- int len = p_str_range.len;
+String &String::operator+=(char32_t p_char) {
+ resize(size() ? size() + 1 : 2);
+ set(length(), 0);
+ if ((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff)) {
+ print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(p_char, 16) + ".");
+ set(length() - 1, 0xfffd);
+ } else {
+ set(length() - 1, p_char);
+ }
+
+ return *this;
+}
+
+bool String::operator==(const char *p_str) const {
+ // compare Latin-1 encoded c-string
+ int len = 0;
+ const char *aux = p_str;
+
+ while (*(aux++) != 0) {
+ len++;
+ }
if (length() != len) {
return false;
@@ -330,12 +524,13 @@ bool String::operator==(const StrRange &p_str_range) const {
return true;
}
- const CharType *c_str = p_str_range.c_str;
- const CharType *dst = &operator[](0);
+ int l = length();
- /* Compare char by char */
- for (int i = 0; i < len; i++) {
- if (c_str[i] != dst[i]) {
+ const char32_t *dst = get_data();
+
+ // Compare char by char
+ for (int i = 0; i < l; i++) {
+ if ((char32_t)p_str[i] != dst[i]) {
return false;
}
}
@@ -343,9 +538,19 @@ bool String::operator==(const StrRange &p_str_range) const {
return true;
}
-bool String::operator==(const char *p_str) const {
+bool String::operator==(const wchar_t *p_str) const {
+#ifdef WINDOWS_ENABLED
+ // wchar_t is 16-bit, parse as UTF-16
+ return *this == String::utf16((const char16_t *)p_str);
+#else
+ // wchar_t is 32-bit, compare char by char
+ return *this == (const char32_t *)p_str;
+#endif
+}
+
+bool String::operator==(const char32_t *p_str) const {
int len = 0;
- const char *aux = p_str;
+ const char32_t *aux = p_str;
while (*(aux++) != 0) {
len++;
@@ -360,7 +565,7 @@ bool String::operator==(const char *p_str) const {
int l = length();
- const CharType *dst = c_str();
+ const char32_t *dst = get_data();
/* Compare char by char */
for (int i = 0; i < l; i++) {
@@ -372,14 +577,32 @@ bool String::operator==(const char *p_str) const {
return true;
}
-bool String::operator==(const CharType *p_str) const {
- int len = 0;
- const CharType *aux = p_str;
+bool String::operator==(const String &p_str) const {
+ if (length() != p_str.length()) {
+ return false;
+ }
+ if (empty()) {
+ return true;
+ }
- while (*(aux++) != 0) {
- len++;
+ int l = length();
+
+ const char32_t *src = get_data();
+ const char32_t *dst = p_str.get_data();
+
+ /* Compare char by char */
+ for (int i = 0; i < l; i++) {
+ if (src[i] != dst[i]) {
+ return false;
+ }
}
+ return true;
+}
+
+bool String::operator==(const StrRange &p_str_range) const {
+ int len = p_str_range.len;
+
if (length() != len) {
return false;
}
@@ -387,13 +610,12 @@ bool String::operator==(const CharType *p_str) const {
return true;
}
- int l = length();
-
- const CharType *dst = c_str();
+ const char32_t *c_str = p_str_range.c_str;
+ const char32_t *dst = &operator[](0);
/* Compare char by char */
- for (int i = 0; i < l; i++) {
- if (p_str[i] != dst[i]) {
+ for (int i = 0; i < len; i++) {
+ if (c_str[i] != dst[i]) {
return false;
}
}
@@ -401,30 +623,68 @@ bool String::operator==(const CharType *p_str) const {
return true;
}
+bool operator==(const char *p_chr, const String &p_str) {
+ return p_str == p_chr;
+}
+
+bool operator==(const wchar_t *p_chr, const String &p_str) {
+#ifdef WINDOWS_ENABLED
+ // wchar_t is 16-bit
+ return p_str == String::utf16((const char16_t *)p_chr);
+#else
+ // wchar_t is 32-bi
+ return p_str == String((const char32_t *)p_chr);
+#endif
+}
+
bool String::operator!=(const char *p_str) const {
return (!(*this == p_str));
}
-bool String::operator!=(const CharType *p_str) const {
+bool String::operator!=(const wchar_t *p_str) const {
return (!(*this == p_str));
}
-bool String::operator<(const CharType *p_str) const {
+bool String::operator!=(const char32_t *p_str) const {
+ return (!(*this == p_str));
+}
+
+bool String::operator!=(const String &p_str) const {
+ return !((*this == p_str));
+}
+
+bool String::operator<=(const String &p_str) const {
+ return (*this < p_str) || (*this == p_str);
+}
+
+bool String::operator<(const char *p_str) const {
if (empty() && p_str[0] == 0) {
return false;
}
if (empty()) {
return true;
}
-
- return is_str_less(c_str(), p_str);
+ return is_str_less(get_data(), p_str);
}
-bool String::operator<=(const String &p_str) const {
- return (*this < p_str) || (*this == p_str);
+bool String::operator<(const wchar_t *p_str) const {
+ if (empty() && p_str[0] == 0) {
+ return false;
+ }
+ if (empty()) {
+ return true;
+ }
+
+#ifdef WINDOWS_ENABLED
+ // wchar_t is 16-bit
+ return is_str_less(get_data(), String::utf16((const char16_t *)p_str).get_data());
+#else
+ // wchar_t is 32-bit
+ return is_str_less(get_data(), (const char32_t *)p_str);
+#endif
}
-bool String::operator<(const char *p_str) const {
+bool String::operator<(const char32_t *p_str) const {
if (empty() && p_str[0] == 0) {
return false;
}
@@ -432,11 +692,11 @@ bool String::operator<(const char *p_str) const {
return true;
}
- return is_str_less(c_str(), p_str);
+ return is_str_less(get_data(), p_str);
}
bool String::operator<(const String &p_str) const {
- return operator<(p_str.c_str());
+ return operator<(p_str.get_data());
}
signed char String::nocasecmp_to(const String &p_str) const {
@@ -450,8 +710,8 @@ signed char String::nocasecmp_to(const String &p_str) const {
return 1;
}
- const CharType *that_str = p_str.c_str();
- const CharType *this_str = c_str();
+ const char32_t *that_str = p_str.get_data();
+ const char32_t *this_str = get_data();
while (true) {
if (*that_str == 0 && *this_str == 0) {
@@ -482,8 +742,8 @@ signed char String::casecmp_to(const String &p_str) const {
return 1;
}
- const CharType *that_str = p_str.c_str();
- const CharType *this_str = c_str();
+ const char32_t *that_str = p_str.get_data();
+ const char32_t *this_str = get_data();
while (true) {
if (*that_str == 0 && *this_str == 0) {
@@ -504,8 +764,8 @@ signed char String::casecmp_to(const String &p_str) const {
}
signed char String::naturalnocasecmp_to(const String &p_str) const {
- const CharType *this_str = c_str();
- const CharType *that_str = p_str.c_str();
+ const char32_t *this_str = get_data();
+ const char32_t *that_str = p_str.get_data();
if (this_str && that_str) {
while (*this_str == '.' || *that_str == '.') {
@@ -571,6 +831,11 @@ signed char String::naturalnocasecmp_to(const String &p_str) const {
return 0;
}
+const char32_t *String::get_data() const {
+ static const char32_t zero = 0;
+ return size() ? &operator[](0) : &zero;
+}
+
void String::erase(int p_pos, int p_chars) {
*this = left(p_pos) + substr(p_pos + p_chars, length() - ((p_pos + p_chars)));
}
@@ -593,7 +858,7 @@ String String::capitalize() const {
}
String String::camelcase_to_underscore(bool lowercase) const {
- const CharType *cstr = c_str();
+ const char32_t *cstr = get_data();
String new_string;
const char A = 'A', Z = 'Z';
const char a = 'a', z = 'z';
@@ -705,7 +970,7 @@ String String::get_slice(String p_splitter, int p_slice) const {
return ""; //no find!
}
-String String::get_slicec(CharType p_splitter, int p_slice) const {
+String String::get_slicec(char32_t p_splitter, int p_slice) const {
if (empty()) {
return String();
}
@@ -714,7 +979,7 @@ String String::get_slicec(CharType p_splitter, int p_slice) const {
return String();
}
- const CharType *c = this->ptr();
+ const char32_t *c = this->ptr();
int i = 0;
int prev = 0;
int count = 0;
@@ -851,7 +1116,7 @@ Vector<float> String::split_floats(const String &p_splitter, bool p_allow_empty)
end = len;
}
if (p_allow_empty || (end > from)) {
- ret.push_back(String::to_float(&c_str()[from]));
+ ret.push_back(String::to_float(&get_data()[from]));
}
if (end == len) {
@@ -880,7 +1145,7 @@ Vector<float> String::split_floats_mk(const Vector<String> &p_splitters, bool p_
}
if (p_allow_empty || (end > from)) {
- ret.push_back(String::to_float(&c_str()[from]));
+ ret.push_back(String::to_float(&get_data()[from]));
}
if (end == len) {
@@ -904,7 +1169,7 @@ Vector<int> String::split_ints(const String &p_splitter, bool p_allow_empty) con
end = len;
}
if (p_allow_empty || (end > from)) {
- ret.push_back(String::to_int(&c_str()[from], end - from));
+ ret.push_back(String::to_int(&get_data()[from], end - from));
}
if (end == len) {
@@ -933,7 +1198,7 @@ Vector<int> String::split_ints_mk(const Vector<String> &p_splitters, bool p_allo
}
if (p_allow_empty || (end > from)) {
- ret.push_back(String::to_int(&c_str()[from], end - from));
+ ret.push_back(String::to_int(&get_data()[from], end - from));
}
if (end == len) {
@@ -946,7 +1211,7 @@ Vector<int> String::split_ints_mk(const Vector<String> &p_splitters, bool p_allo
return ret;
}
-String String::join(Vector<String> parts) {
+String String::join(Vector<String> parts) const {
String ret;
for (int i = 0; i < parts.size(); ++i) {
if (i > 0) {
@@ -957,11 +1222,11 @@ String String::join(Vector<String> parts) {
return ret;
}
-CharType String::char_uppercase(CharType p_char) {
+char32_t String::char_uppercase(char32_t p_char) {
return _find_upper(p_char);
}
-CharType String::char_lowercase(CharType p_char) {
+char32_t String::char_lowercase(char32_t p_char) {
return _find_lower(p_char);
}
@@ -969,8 +1234,8 @@ String String::to_upper() const {
String upper = *this;
for (int i = 0; i < upper.size(); i++) {
- const CharType s = upper[i];
- const CharType t = _find_upper(s);
+ const char32_t s = upper[i];
+ const char32_t t = _find_upper(s);
if (s != t) { // avoid copy on write
upper[i] = t;
}
@@ -983,8 +1248,8 @@ String String::to_lower() const {
String lower = *this;
for (int i = 0; i < lower.size(); i++) {
- const CharType s = lower[i];
- const CharType t = _find_lower(s);
+ const char32_t s = lower[i];
+ const char32_t t = _find_lower(s);
if (s != t) { // avoid copy on write
lower[i] = t;
}
@@ -993,34 +1258,8 @@ String String::to_lower() const {
return lower;
}
-const CharType *String::c_str() const {
- static const CharType zero = 0;
-
- return size() ? &operator[](0) : &zero;
-}
-
-String String::md5(const uint8_t *p_md5) {
- return String::hex_encode_buffer(p_md5, 16);
-}
-
-String String::hex_encode_buffer(const uint8_t *p_buffer, int p_len) {
- static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-
- String ret;
- char v[2] = { 0, 0 };
-
- for (int i = 0; i < p_len; i++) {
- v[0] = hex[p_buffer[i] >> 4];
- ret += v;
- v[0] = hex[p_buffer[i] & 0xF];
- ret += v;
- }
-
- return ret;
-}
-
-String String::chr(CharType p_char) {
- CharType c[2] = { p_char, 0 };
+String String::chr(char32_t p_char) {
+ char32_t c[2] = { p_char, 0 };
return String(c);
}
@@ -1028,6 +1267,14 @@ String String::num(double p_num, int p_decimals) {
if (Math::is_nan(p_num)) {
return "nan";
}
+
+ if (Math::is_inf(p_num)) {
+ if (signbit(p_num)) {
+ return "-inf";
+ } else {
+ return "inf";
+ }
+ }
#ifndef NO_USE_STDLIB
if (p_decimals > 16) {
@@ -1106,7 +1353,7 @@ String String::num(double p_num, int p_decimals) {
/* decimal part */
if (p_decimals > 0 || (p_decimals == -1 && (int)p_num != p_num)) {
- double dec = p_num - (float)((int)p_num);
+ double dec = p_num - (double)((int)p_num);
int digit = 0;
if (p_decimals > MAX_DIGITS)
@@ -1125,7 +1372,7 @@ String String::num(double p_num, int p_decimals) {
if (digit == MAX_DIGITS) //no point in going to infinite
break;
- if ((dec - (float)((int)dec)) < 1e-6)
+ if ((dec - (double)((int)dec)) < 1e-6)
break;
}
@@ -1159,7 +1406,7 @@ String String::num(double p_num, int p_decimals) {
s = "0";
else {
while (intn) {
- CharType num = '0' + (intn % 10);
+ char32_t num = '0' + (intn % 10);
intn /= 10;
s = num + s;
}
@@ -1188,7 +1435,7 @@ String String::num_int64(int64_t p_num, int base, bool capitalize_hex) {
}
String s;
s.resize(chars + 1);
- CharType *c = s.ptrw();
+ char32_t *c = s.ptrw();
c[chars] = 0;
n = p_num;
do {
@@ -1221,7 +1468,7 @@ String String::num_uint64(uint64_t p_num, int base, bool capitalize_hex) {
String s;
s.resize(chars + 1);
- CharType *c = s.ptrw();
+ char32_t *c = s.ptrw();
c[chars] = 0;
n = p_num;
do {
@@ -1240,6 +1487,18 @@ String String::num_uint64(uint64_t p_num, int base, bool capitalize_hex) {
}
String String::num_real(double p_num) {
+ if (Math::is_nan(p_num)) {
+ return "nan";
+ }
+
+ if (Math::is_inf(p_num)) {
+ if (signbit(p_num)) {
+ return "-inf";
+ } else {
+ return "inf";
+ }
+ }
+
String s;
String sd;
/* integer part */
@@ -1251,7 +1510,7 @@ String String::num_real(double p_num) {
/* decimal part */
if ((int)p_num != p_num) {
- double dec = p_num - (float)((int)p_num);
+ double dec = p_num - (double)((int)p_num);
int digit = 0;
int decimals = MAX_DIGITS;
@@ -1265,7 +1524,7 @@ String String::num_real(double p_num) {
dec_max = dec_max * 10 + 9;
digit++;
- if ((dec - (float)((int)dec)) < 1e-6) {
+ if ((dec - (double)((int)dec)) < 1e-6) {
break;
}
@@ -1302,7 +1561,7 @@ String String::num_real(double p_num) {
s = "0";
} else {
while (intn) {
- CharType num = '0' + (intn % 10);
+ char32_t num = '0' + (intn % 10);
intn /= 10;
s = num + s;
}
@@ -1319,6 +1578,14 @@ String String::num_scientific(double p_num) {
if (Math::is_nan(p_num)) {
return "nan";
}
+
+ if (Math::is_inf(p_num)) {
+ if (signbit(p_num)) {
+ return "-inf";
+ } else {
+ return "inf";
+ }
+ }
#ifndef NO_USE_STDLIB
char buf[256];
@@ -1348,6 +1615,26 @@ String String::num_scientific(double p_num) {
#endif
}
+String String::md5(const uint8_t *p_md5) {
+ return String::hex_encode_buffer(p_md5, 16);
+}
+
+String String::hex_encode_buffer(const uint8_t *p_buffer, int p_len) {
+ static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+ String ret;
+ char v[2] = { 0, 0 };
+
+ for (int i = 0; i < p_len; i++) {
+ v[0] = hex[p_buffer[i] >> 4];
+ ret += v;
+ v[0] = hex[p_buffer[i] & 0xF];
+ ret += v;
+ }
+
+ return ret;
+}
+
CharString String::ascii(bool p_allow_extended) const {
if (!length()) {
return CharString();
@@ -1357,7 +1644,13 @@ CharString String::ascii(bool p_allow_extended) const {
cs.resize(size());
for (int i = 0; i < size(); i++) {
- cs[i] = operator[](i);
+ char32_t c = operator[](i);
+ if ((c <= 0x7f) || (c <= 0xff && p_allow_extended)) {
+ cs[i] = c;
+ } else {
+ print_error("Unicode parsing error: Cannot represent " + num_int64(c, 16) + " as ASCII/Latin-1 character.");
+ cs[i] = 0x20;
+ }
}
return cs;
@@ -1371,7 +1664,7 @@ String String::utf8(const char *p_utf8, int p_len) {
}
bool String::parse_utf8(const char *p_utf8, int p_len) {
-#define _UNICERROR(m_err) print_line("Unicode parsing error: " + String(m_err) + ". Is the string valid UTF-8?");
+#define _UNICERROR(m_err) print_error("Unicode parsing error: " + String(m_err) + ". Is the string valid UTF-8?");
if (!p_utf8) {
return true;
@@ -1384,9 +1677,9 @@ bool String::parse_utf8(const char *p_utf8, int p_len) {
/* HANDLE BOM (Byte Order Mark) */
if (p_len < 0 || p_len >= 3) {
- bool has_bom = uint8_t(p_utf8[0]) == 0xEF && uint8_t(p_utf8[1]) == 0xBB && uint8_t(p_utf8[2]) == 0xBF;
+ bool has_bom = uint8_t(p_utf8[0]) == 0xef && uint8_t(p_utf8[1]) == 0xbb && uint8_t(p_utf8[2]) == 0xbf;
if (has_bom) {
- //just skip it
+ //8-bit encoding, byte order has no meaning in UTF-8, just skip it
if (p_len >= 0) {
p_len -= 3;
}
@@ -1405,24 +1698,19 @@ bool String::parse_utf8(const char *p_utf8, int p_len) {
/* Determine the number of characters in sequence */
if ((c & 0x80) == 0) {
skip = 0;
- } else if ((c & 0xE0) == 0xC0) {
+ } else if ((c & 0xe0) == 0xc0) {
skip = 1;
- } else if ((c & 0xF0) == 0xE0) {
+ } else if ((c & 0xf0) == 0xe0) {
skip = 2;
- } else if ((c & 0xF8) == 0xF0) {
+ } else if ((c & 0xf8) == 0xf0) {
skip = 3;
- } else if ((c & 0xFC) == 0xF8) {
- skip = 4;
- } else if ((c & 0xFE) == 0xFC) {
- skip = 5;
} else {
- _UNICERROR("invalid skip");
+ _UNICERROR("invalid skip at " + num_int64(cstr_size));
return true; //invalid utf8
}
- if (skip == 1 && (c & 0x1E) == 0) {
- //printf("overlong rejected\n");
- _UNICERROR("overlong rejected");
+ if (skip == 1 && (c & 0x1e) == 0) {
+ _UNICERROR("overlong rejected at " + num_int64(cstr_size));
return true; //reject overlong
}
@@ -1448,7 +1736,7 @@ bool String::parse_utf8(const char *p_utf8, int p_len) {
}
resize(str_size + 1);
- CharType *dst = ptrw();
+ char32_t *dst = ptrw();
dst[str_size] = 0;
while (cstr_size) {
@@ -1457,19 +1745,14 @@ bool String::parse_utf8(const char *p_utf8, int p_len) {
/* Determine the number of characters in sequence */
if ((*p_utf8 & 0x80) == 0) {
len = 1;
- } else if ((*p_utf8 & 0xE0) == 0xC0) {
+ } else if ((*p_utf8 & 0xe0) == 0xc0) {
len = 2;
- } else if ((*p_utf8 & 0xF0) == 0xE0) {
+ } else if ((*p_utf8 & 0xf0) == 0xe0) {
len = 3;
- } else if ((*p_utf8 & 0xF8) == 0xF0) {
+ } else if ((*p_utf8 & 0xf8) == 0xf0) {
len = 4;
- } else if ((*p_utf8 & 0xFC) == 0xF8) {
- len = 5;
- } else if ((*p_utf8 & 0xFE) == 0xFC) {
- len = 6;
} else {
_UNICERROR("invalid len");
-
return true; //invalid UTF8
}
@@ -1479,7 +1762,6 @@ bool String::parse_utf8(const char *p_utf8, int p_len) {
}
if (len == 2 && (*p_utf8 & 0x1E) == 0) {
- //printf("overlong rejected\n");
_UNICERROR("no space left");
return true; //reject overlong
}
@@ -1491,24 +1773,23 @@ bool String::parse_utf8(const char *p_utf8, int p_len) {
if (len == 1) {
unichar = *p_utf8;
} else {
- unichar = (0xFF >> (len + 1)) & *p_utf8;
+ unichar = (0xff >> (len + 1)) & *p_utf8;
for (int i = 1; i < len; i++) {
- if ((p_utf8[i] & 0xC0) != 0x80) {
+ if ((p_utf8[i] & 0xc0) != 0x80) {
_UNICERROR("invalid utf8");
return true; //invalid utf8
}
- if (unichar == 0 && i == 2 && ((p_utf8[i] & 0x7F) >> (7 - len)) == 0) {
+ if (unichar == 0 && i == 2 && ((p_utf8[i] & 0x7f) >> (7 - len)) == 0) {
_UNICERROR("invalid utf8 overlong");
return true; //no overlong
}
- unichar = (unichar << 6) | (p_utf8[i] & 0x3F);
+ unichar = (unichar << 6) | (p_utf8[i] & 0x3f);
}
}
-
- //printf("char %i, len %i\n",unichar,len);
- if (sizeof(wchar_t) == 2 && unichar > 0xFFFF) {
- unichar = ' '; //too long for windows
+ if (unichar >= 0xd800 && unichar <= 0xdfff) {
+ _UNICERROR("invalid code point");
+ return CharString();
}
*(dst++) = unichar;
@@ -1517,6 +1798,7 @@ bool String::parse_utf8(const char *p_utf8, int p_len) {
}
return false;
+#undef _UNICERROR
}
CharString String::utf8() const {
@@ -1525,7 +1807,7 @@ CharString String::utf8() const {
return CharString();
}
- const CharType *d = &operator[](0);
+ const char32_t *d = &operator[](0);
int fl = 0;
for (int i = 0; i < l; i++) {
uint32_t c = d[i];
@@ -1535,13 +1817,15 @@ CharString String::utf8() const {
fl += 2;
} else if (c <= 0xffff) { // 16 bits
fl += 3;
- } else if (c <= 0x001fffff) { // 21 bits
+ } else if (c <= 0x0010ffff) { // 21 bits
fl += 4;
-
- } else if (c <= 0x03ffffff) { // 26 bits
- fl += 5;
- } else if (c <= 0x7fffffff) { // 31 bits
- fl += 6;
+ } else {
+ print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(c, 16) + ".");
+ return CharString();
+ }
+ if (c >= 0xd800 && c <= 0xdfff) {
+ print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(c, 16) + ".");
+ return CharString();
}
}
@@ -1561,35 +1845,17 @@ CharString String::utf8() const {
if (c <= 0x7f) { // 7 bits.
APPEND_CHAR(c);
} else if (c <= 0x7ff) { // 11 bits
-
APPEND_CHAR(uint32_t(0xc0 | ((c >> 6) & 0x1f))); // Top 5 bits.
APPEND_CHAR(uint32_t(0x80 | (c & 0x3f))); // Bottom 6 bits.
} else if (c <= 0xffff) { // 16 bits
-
APPEND_CHAR(uint32_t(0xe0 | ((c >> 12) & 0x0f))); // Top 4 bits.
APPEND_CHAR(uint32_t(0x80 | ((c >> 6) & 0x3f))); // Middle 6 bits.
APPEND_CHAR(uint32_t(0x80 | (c & 0x3f))); // Bottom 6 bits.
- } else if (c <= 0x001fffff) { // 21 bits
-
+ } else { // 21 bits
APPEND_CHAR(uint32_t(0xf0 | ((c >> 18) & 0x07))); // Top 3 bits.
APPEND_CHAR(uint32_t(0x80 | ((c >> 12) & 0x3f))); // Upper middle 6 bits.
APPEND_CHAR(uint32_t(0x80 | ((c >> 6) & 0x3f))); // Lower middle 6 bits.
APPEND_CHAR(uint32_t(0x80 | (c & 0x3f))); // Bottom 6 bits.
- } else if (c <= 0x03ffffff) { // 26 bits
-
- APPEND_CHAR(uint32_t(0xf8 | ((c >> 24) & 0x03))); // Top 2 bits.
- APPEND_CHAR(uint32_t(0x80 | ((c >> 18) & 0x3f))); // Upper middle 6 bits.
- APPEND_CHAR(uint32_t(0x80 | ((c >> 12) & 0x3f))); // middle 6 bits.
- APPEND_CHAR(uint32_t(0x80 | ((c >> 6) & 0x3f))); // Lower middle 6 bits.
- APPEND_CHAR(uint32_t(0x80 | (c & 0x3f))); // Bottom 6 bits.
- } else if (c <= 0x7fffffff) { // 31 bits
-
- APPEND_CHAR(uint32_t(0xfc | ((c >> 30) & 0x01))); // Top 1 bit.
- APPEND_CHAR(uint32_t(0x80 | ((c >> 24) & 0x3f))); // Upper upper middle 6 bits.
- APPEND_CHAR(uint32_t(0x80 | ((c >> 18) & 0x3f))); // Lower upper middle 6 bits.
- APPEND_CHAR(uint32_t(0x80 | ((c >> 12) & 0x3f))); // Upper lower middle 6 bits.
- APPEND_CHAR(uint32_t(0x80 | ((c >> 6) & 0x3f))); // Lower lower middle 6 bits.
- APPEND_CHAR(uint32_t(0x80 | (c & 0x3f))); // Bottom 6 bits.
}
}
#undef APPEND_CHAR
@@ -1598,21 +1864,191 @@ CharString String::utf8() const {
return utf8s;
}
-/*
-String::String(CharType p_char) {
+String String::utf16(const char16_t *p_utf16, int p_len) {
+ String ret;
+ ret.parse_utf16(p_utf16, p_len);
+
+ return ret;
+}
+
+bool String::parse_utf16(const char16_t *p_utf16, int p_len) {
+#define _UNICERROR(m_err) print_error("Unicode parsing error: " + String(m_err) + ". Is the string valid UTF-16?");
+
+ if (!p_utf16) {
+ return true;
+ }
+
+ String aux;
+
+ int cstr_size = 0;
+ int str_size = 0;
+
+ /* HANDLE BOM (Byte Order Mark) */
+ bool byteswap = false; // assume correct endianness if no BOM found
+ if (p_len < 0 || p_len >= 1) {
+ bool has_bom = false;
+ if (uint16_t(p_utf16[0]) == 0xfeff) { // correct BOM, read as is
+ has_bom = true;
+ byteswap = false;
+ } else if (uint16_t(p_utf16[0]) == 0xfffe) { // backwards BOM, swap bytes
+ has_bom = true;
+ byteswap = true;
+ }
+ if (has_bom) {
+ if (p_len >= 0) {
+ p_len -= 1;
+ }
+ p_utf16 += 1;
+ }
+ }
+
+ {
+ const char16_t *ptrtmp = p_utf16;
+ const char16_t *ptrtmp_limit = &p_utf16[p_len];
+ int skip = 0;
+ while (ptrtmp != ptrtmp_limit && *ptrtmp) {
+ uint32_t c = (byteswap) ? BSWAP16(*ptrtmp) : *ptrtmp;
+ if (skip == 0) {
+ if ((c & 0xfffffc00) == 0xd800) {
+ skip = 1; // lead surrogate
+ } else if ((c & 0xfffffc00) == 0xdc00) {
+ _UNICERROR("invalid utf16 surrogate at " + num_int64(cstr_size));
+ return true; // invalid UTF16
+ } else {
+ skip = 0;
+ }
+ str_size++;
+ } else {
+ if ((c & 0xfffffc00) == 0xdc00) { // trail surrogate
+ --skip;
+ } else {
+ _UNICERROR("invalid utf16 surrogate at " + num_int64(cstr_size));
+ return true; // invalid UTF16
+ }
+ }
+
+ cstr_size++;
+ ptrtmp++;
+ }
+
+ if (skip) {
+ _UNICERROR("no space left");
+ return true; // not enough space
+ }
+ }
+
+ if (str_size == 0) {
+ clear();
+ return false;
+ }
+
+ resize(str_size + 1);
+ char32_t *dst = ptrw();
+ dst[str_size] = 0;
+
+ while (cstr_size) {
+ int len = 0;
+ uint32_t c = (byteswap) ? BSWAP16(*p_utf16) : *p_utf16;
+
+ if ((c & 0xfffffc00) == 0xd800) {
+ len = 2;
+ } else {
+ len = 1;
+ }
+
+ if (len > cstr_size) {
+ _UNICERROR("no space left");
+ return true; //not enough space
+ }
+
+ uint32_t unichar = 0;
+ if (len == 1) {
+ unichar = c;
+ } else {
+ uint32_t c2 = (byteswap) ? BSWAP16(p_utf16[1]) : p_utf16[1];
+ unichar = (c << 10UL) + c2 - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
+ }
+
+ *(dst++) = unichar;
+ cstr_size -= len;
+ p_utf16 += len;
+ }
- shared=nullptr;
- copy_from(p_char);
+ return false;
+#undef _UNICERROR
}
+Char16String String::utf16() const {
+ int l = length();
+ if (!l) {
+ return Char16String();
+ }
-*/
+ const char32_t *d = &operator[](0);
+ int fl = 0;
+ for (int i = 0; i < l; i++) {
+ uint32_t c = d[i];
+ if (c <= 0xffff) { // 16 bits.
+ fl += 1;
+ } else if (c <= 0x10ffff) { // 32 bits.
+ fl += 2;
+ } else {
+ print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(c, 16) + ".");
+ return Char16String();
+ }
+ if (c >= 0xd800 && c <= 0xdfff) {
+ print_error("Unicode parsing error: Invalid unicode codepoint " + num_int64(c, 16) + ".");
+ return Char16String();
+ }
+ }
+
+ Char16String utf16s;
+ if (fl == 0) {
+ return utf16s;
+ }
+
+ utf16s.resize(fl + 1);
+ uint16_t *cdst = (uint16_t *)utf16s.get_data();
+
+#define APPEND_CHAR(m_c) *(cdst++) = m_c
+
+ for (int i = 0; i < l; i++) {
+ uint32_t c = d[i];
+
+ if (c <= 0xffff) { // 16 bits.
+ APPEND_CHAR(c);
+ } else { // 32 bits.
+ APPEND_CHAR(uint32_t((c >> 10) + 0xd7c0)); // lead surrogate.
+ APPEND_CHAR(uint32_t((c & 0x3ff) | 0xdc00)); // trail surrogate.
+ }
+ }
+#undef APPEND_CHAR
+ *cdst = 0; //trailing zero
+
+ return utf16s;
+}
String::String(const char *p_str) {
copy_from(p_str);
}
-String::String(const CharType *p_str, int p_clip_to_len) {
+String::String(const wchar_t *p_str) {
+ copy_from(p_str);
+}
+
+String::String(const char32_t *p_str) {
+ copy_from(p_str);
+}
+
+String::String(const char *p_str, int p_clip_to_len) {
+ copy_from(p_str, p_clip_to_len);
+}
+
+String::String(const wchar_t *p_str, int p_clip_to_len) {
+ copy_from(p_str, p_clip_to_len);
+}
+
+String::String(const char32_t *p_str, int p_clip_to_len) {
copy_from(p_str, p_clip_to_len);
}
@@ -1620,7 +2056,6 @@ String::String(const StrRange &p_range) {
if (!p_range.c_str) {
return;
}
-
copy_from(p_range.c_str, p_range.len);
}
@@ -1629,7 +2064,7 @@ int64_t String::hex_to_int(bool p_with_prefix) const {
return 0;
}
- const CharType *s = ptr();
+ const char32_t *s = ptr();
int64_t sign = s[0] == '-' ? -1 : 1;
@@ -1647,7 +2082,7 @@ int64_t String::hex_to_int(bool p_with_prefix) const {
int64_t hex = 0;
while (*s) {
- CharType c = LOWERCASE(*s);
+ char32_t c = LOWERCASE(*s);
int64_t n;
if (c >= '0' && c <= '9') {
n = c - '0';
@@ -1672,7 +2107,7 @@ int64_t String::bin_to_int(bool p_with_prefix) const {
return 0;
}
- const CharType *s = ptr();
+ const char32_t *s = ptr();
int64_t sign = s[0] == '-' ? -1 : 1;
@@ -1690,7 +2125,7 @@ int64_t String::bin_to_int(bool p_with_prefix) const {
int64_t binary = 0;
while (*s) {
- CharType c = LOWERCASE(*s);
+ char32_t c = LOWERCASE(*s);
int64_t n;
if (c == '0' || c == '1') {
n = c - '0';
@@ -1719,7 +2154,7 @@ int64_t String::to_int() const {
int64_t sign = 1;
for (int i = 0; i < to; i++) {
- CharType c = operator[](i);
+ char32_t c = operator[](i);
if (c >= '0' && c <= '9') {
bool overflow = (integer > INT64_MAX / 10) || (integer == INT64_MAX / 10 && ((sign == 1 && c > '7') || (sign == -1 && c > '8')));
ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + *this + " as 64-bit integer, provided value is " + (sign == 1 ? "too big." : "too small."));
@@ -1765,6 +2200,37 @@ int64_t String::to_int(const char *p_str, int p_len) {
return integer * sign;
}
+int64_t String::to_int(const wchar_t *p_str, int p_len) {
+ int to = 0;
+ if (p_len >= 0) {
+ to = p_len;
+ } else {
+ while (p_str[to] != 0 && p_str[to] != '.') {
+ to++;
+ }
+ }
+
+ int64_t integer = 0;
+ int64_t sign = 1;
+
+ for (int i = 0; i < to; i++) {
+ wchar_t c = p_str[i];
+ if (c >= '0' && c <= '9') {
+ bool overflow = (integer > INT64_MAX / 10) || (integer == INT64_MAX / 10 && ((sign == 1 && c > '7') || (sign == -1 && c > '8')));
+ ERR_FAIL_COND_V_MSG(overflow, sign == 1 ? INT64_MAX : INT64_MIN, "Cannot represent " + String(p_str).substr(0, to) + " as integer, provided value is " + (sign == 1 ? "too big." : "too small."));
+ integer *= 10;
+ integer += c - '0';
+
+ } else if (c == '-' && integer == 0) {
+ sign = -sign;
+ } else if (c != ' ') {
+ break;
+ }
+ }
+
+ return integer * sign;
+}
+
bool String::is_numeric() const {
if (length() == 0) {
return false;
@@ -1776,14 +2242,13 @@ bool String::is_numeric() const {
}
bool dot = false;
for (int i = s; i < length(); i++) {
- CharType c = operator[](i);
+ char32_t c = operator[](i);
if (c == '.') {
if (dot) {
return false;
}
dot = true;
- }
- if (c < '0' || c > '9') {
+ } else if (c < '0' || c > '9') {
return false;
}
}
@@ -1945,11 +2410,11 @@ static double built_in_strtod(const C *string, /* A decimal ASCII floating-point
}
expSign = false;
}
- if (!IS_DIGIT(CharType(*p))) {
+ if (!IS_DIGIT(char32_t(*p))) {
p = pExp;
goto done;
}
- while (IS_DIGIT(CharType(*p))) {
+ while (IS_DIGIT(char32_t(*p))) {
exp = exp * 10 + (*p - '0');
p += 1;
}
@@ -2007,19 +2472,18 @@ done:
#define READING_DONE 4
double String::to_float(const char *p_str) {
-#ifndef NO_USE_STDLIB
- return built_in_strtod<char>(p_str);
-//return atof(p_str); DOES NOT WORK ON ANDROID(??)
-#else
return built_in_strtod<char>(p_str);
-#endif
}
-double String::to_float(const CharType *p_str, const CharType **r_end) {
- return built_in_strtod<CharType>(p_str, (CharType **)r_end);
+double String::to_float(const char32_t *p_str, const char32_t **r_end) {
+ return built_in_strtod<char32_t>(p_str, (char32_t **)r_end);
}
-int64_t String::to_int(const CharType *p_str, int p_len, bool p_clamp) {
+double String::to_float(const wchar_t *p_str, const wchar_t **r_end) {
+ return built_in_strtod<wchar_t>(p_str, (wchar_t **)r_end);
+}
+
+int64_t String::to_int(const char32_t *p_str, int p_len, bool p_clamp) {
if (p_len == 0 || !p_str[0]) {
return 0;
}
@@ -2029,11 +2493,11 @@ int64_t String::to_int(const CharType *p_str, int p_len, bool p_clamp) {
int64_t sign = 1;
int reading = READING_SIGN;
- const CharType *str = p_str;
- const CharType *limit = &p_str[p_len];
+ const char32_t *str = p_str;
+ const char32_t *limit = &p_str[p_len];
while (*str && reading != READING_DONE && str != limit) {
- CharType c = *(str++);
+ char32_t c = *(str++);
switch (reading) {
case READING_SIGN: {
if (c >= '0' && c <= '9') {
@@ -2087,26 +2551,7 @@ double String::to_float() const {
if (empty()) {
return 0;
}
-#ifndef NO_USE_STDLIB
- return built_in_strtod<CharType>(c_str());
-//return wcstod(c_str(),nullptr ); DOES NOT WORK ON ANDROID :(
-#else
- return built_in_strtod<CharType>(c_str());
-#endif
-}
-
-bool operator==(const char *p_chr, const String &p_str) {
- return p_str == p_chr;
-}
-
-String operator+(const char *p_chr, const String &p_str) {
- String tmp = p_chr;
- tmp += p_str;
- return tmp;
-}
-
-String operator+(CharType p_chr, const String &p_str) {
- return (String::chr(p_chr) + p_str);
+ return built_in_strtod<char32_t>(get_data());
}
uint32_t String::hash(const char *p_cstr) {
@@ -2129,7 +2574,27 @@ uint32_t String::hash(const char *p_cstr, int p_len) {
return hashv;
}
-uint32_t String::hash(const CharType *p_cstr, int p_len) {
+uint32_t String::hash(const wchar_t *p_cstr, int p_len) {
+ uint32_t hashv = 5381;
+ for (int i = 0; i < p_len; i++) {
+ hashv = ((hashv << 5) + hashv) + p_cstr[i]; /* hash * 33 + c */
+ }
+
+ return hashv;
+}
+
+uint32_t String::hash(const wchar_t *p_cstr) {
+ uint32_t hashv = 5381;
+ uint32_t c;
+
+ while ((c = *p_cstr++)) {
+ hashv = ((hashv << 5) + hashv) + c; /* hash * 33 + c */
+ }
+
+ return hashv;
+}
+
+uint32_t String::hash(const char32_t *p_cstr, int p_len) {
uint32_t hashv = 5381;
for (int i = 0; i < p_len; i++) {
hashv = ((hashv << 5) + hashv) + p_cstr[i]; /* hash * 33 + c */
@@ -2138,7 +2603,7 @@ uint32_t String::hash(const CharType *p_cstr, int p_len) {
return hashv;
}
-uint32_t String::hash(const CharType *p_cstr) {
+uint32_t String::hash(const char32_t *p_cstr) {
uint32_t hashv = 5381;
uint32_t c;
@@ -2152,7 +2617,7 @@ uint32_t String::hash(const CharType *p_cstr) {
uint32_t String::hash() const {
/* simple djb2 hashing */
- const CharType *chr = c_str();
+ const char32_t *chr = get_data();
uint32_t hashv = 5381;
uint32_t c;
@@ -2166,7 +2631,7 @@ uint32_t String::hash() const {
uint64_t String::hash64() const {
/* simple djb2 hashing */
- const CharType *chr = c_str();
+ const char32_t *chr = get_data();
uint64_t hashv = 5381;
uint64_t c;
@@ -2278,7 +2743,7 @@ String String::substr(int p_from, int p_chars) const {
}
String s = String();
- s.copy_from_unchecked(&c_str()[p_from], p_chars);
+ s.copy_from_unchecked(&get_data()[p_from], p_chars);
return s;
}
@@ -2295,8 +2760,8 @@ int String::find(const String &p_str, int p_from) const {
return -1; // won't find anything!
}
- const CharType *src = c_str();
- const CharType *str = p_str.c_str();
+ const char32_t *src = get_data();
+ const char32_t *str = p_str.get_data();
for (int i = p_from; i <= (len - src_len); i++) {
bool found = true;
@@ -2333,7 +2798,7 @@ int String::find(const char *p_str, int p_from) const {
return -1; // won't find anything!
}
- const CharType *src = c_str();
+ const char32_t *src = get_data();
int src_len = 0;
while (p_str[src_len] != '\0') {
@@ -2341,7 +2806,7 @@ int String::find(const char *p_str, int p_from) const {
}
if (src_len == 1) {
- const char needle = p_str[0];
+ const char32_t needle = p_str[0];
for (int i = p_from; i < len; i++) {
if (src[i] == needle) {
@@ -2360,7 +2825,7 @@ int String::find(const char *p_str, int p_from) const {
return -1;
}
- if (src[read_pos] != p_str[j]) {
+ if (src[read_pos] != (char32_t)p_str[j]) {
found = false;
break;
}
@@ -2375,7 +2840,7 @@ int String::find(const char *p_str, int p_from) const {
return -1;
}
-int String::find_char(const CharType &p_char, int p_from) const {
+int String::find_char(const char32_t &p_char, int p_from) const {
return _cowdata.find(p_char, p_from);
}
@@ -2396,7 +2861,7 @@ int String::findmk(const Vector<String> &p_keys, int p_from, int *r_key) const {
return -1; // won't find anything!
}
- const CharType *src = c_str();
+ const char32_t *src = get_data();
for (int i = p_from; i < len; i++) {
bool found = true;
@@ -2405,7 +2870,7 @@ int String::findmk(const Vector<String> &p_keys, int p_from, int *r_key) const {
if (r_key) {
*r_key = k;
}
- const CharType *cmp = keys[k].c_str();
+ const char32_t *cmp = keys[k].get_data();
int l = keys[k].length();
for (int j = 0; j < l; j++) {
@@ -2445,7 +2910,7 @@ int String::findn(const String &p_str, int p_from) const {
return -1; // won't find anything!
}
- const CharType *srcd = c_str();
+ const char32_t *srcd = get_data();
for (int i = p_from; i <= (length() - src_len); i++) {
bool found = true;
@@ -2457,8 +2922,8 @@ int String::findn(const String &p_str, int p_from) const {
return -1;
}
- CharType src = _find_lower(srcd[read_pos]);
- CharType dst = _find_lower(p_str[j]);
+ char32_t src = _find_lower(srcd[read_pos]);
+ char32_t dst = _find_lower(p_str[j]);
if (src != dst) {
found = false;
@@ -2495,7 +2960,7 @@ int String::rfind(const String &p_str, int p_from) const {
return -1; // won't find anything!
}
- const CharType *src = c_str();
+ const char32_t *src = get_data();
for (int i = p_from; i >= 0; i--) {
bool found = true;
@@ -2542,7 +3007,7 @@ int String::rfindn(const String &p_str, int p_from) const {
return -1; // won't find anything!
}
- const CharType *src = c_str();
+ const char32_t *src = get_data();
for (int i = p_from; i >= 0; i--) {
bool found = true;
@@ -2554,8 +3019,8 @@ int String::rfindn(const String &p_str, int p_from) const {
return -1;
}
- CharType srcc = _find_lower(src[read_pos]);
- CharType dstc = _find_lower(p_str[j]);
+ char32_t srcc = _find_lower(src[read_pos]);
+ char32_t dstc = _find_lower(p_str[j]);
if (srcc != dstc) {
found = false;
@@ -2589,8 +3054,8 @@ bool String::begins_with(const String &p_string) const {
return true;
}
- const CharType *src = &p_string[0];
- const CharType *str = &operator[](0);
+ const char32_t *src = &p_string[0];
+ const char32_t *str = &operator[](0);
int i = 0;
for (; i < l; i++) {
@@ -2609,11 +3074,11 @@ bool String::begins_with(const char *p_string) const {
return false;
}
- const CharType *str = &operator[](0);
+ const char32_t *str = &operator[](0);
int i = 0;
while (*p_string && i < l) {
- if (*p_string != str[i]) {
+ if ((char32_t)*p_string != str[i]) {
return false;
}
i++;
@@ -2657,7 +3122,7 @@ int String::_count(const String &p_string, int p_from, int p_to, bool p_case_ins
}
if (p_from == 0 && p_to == len) {
str = String();
- str.copy_from_unchecked(&c_str()[0], len);
+ str.copy_from_unchecked(&get_data()[0], len);
} else {
str = substr(p_from, p_to - p_from);
}
@@ -2695,14 +3160,14 @@ bool String::_base_is_subsequence_of(const String &p_string, bool case_insensiti
return false;
}
- const CharType *src = &operator[](0);
- const CharType *tgt = &p_string[0];
+ const char32_t *src = &operator[](0);
+ const char32_t *tgt = &p_string[0];
for (; *src && *tgt; tgt++) {
bool match = false;
if (case_insensitive) {
- CharType srcc = _find_lower(*src);
- CharType tgtc = _find_lower(*tgt);
+ char32_t srcc = _find_lower(*src);
+ char32_t tgtc = _find_lower(*tgt);
match = srcc == tgtc;
} else {
match = *src == *tgt;
@@ -2748,8 +3213,8 @@ float String::similarity(const String &p_string) const {
int src_size = src_bigrams.size();
int tgt_size = tgt_bigrams.size();
- float sum = src_size + tgt_size;
- float inter = 0;
+ double sum = src_size + tgt_size;
+ double inter = 0;
for (int i = 0; i < src_size; i++) {
for (int j = 0; j < tgt_size; j++) {
if (src_bigrams[i] == tgt_bigrams[j]) {
@@ -2762,7 +3227,7 @@ float String::similarity(const String &p_string) const {
return (2.0f * inter) / sum;
}
-static bool _wildcard_match(const CharType *p_pattern, const CharType *p_string, bool p_case_sensitive) {
+static bool _wildcard_match(const char32_t *p_pattern, const char32_t *p_string, bool p_case_sensitive) {
switch (*p_pattern) {
case '\0':
return !*p_string;
@@ -2781,14 +3246,14 @@ bool String::match(const String &p_wildcard) const {
return false;
}
- return _wildcard_match(p_wildcard.c_str(), c_str(), true);
+ return _wildcard_match(p_wildcard.get_data(), get_data(), true);
}
bool String::matchn(const String &p_wildcard) const {
if (!p_wildcard.length() || !length()) {
return false;
}
- return _wildcard_match(p_wildcard.c_str(), c_str(), false);
+ return _wildcard_match(p_wildcard.get_data(), get_data(), false);
}
String String::format(const Variant &values, String placeholder) const {
@@ -2938,9 +3403,10 @@ String String::repeat(int p_count) const {
ERR_FAIL_COND_V_MSG(p_count < 0, "", "Parameter count should be a positive number.");
String new_string;
- const CharType *src = this->c_str();
+ const char32_t *src = this->get_data();
new_string.resize(length() * p_count + 1);
+ new_string[length() * p_count] = 0;
for (int i = 0; i < p_count; i++) {
for (int j = 0; j < length(); j++) {
@@ -2975,7 +3441,7 @@ String String::right(int p_pos) const {
return substr(p_pos, (length() - p_pos));
}
-CharType String::ord_at(int p_idx) const {
+char32_t String::ord_at(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, length(), 0);
return operator[](p_idx);
}
@@ -2989,7 +3455,7 @@ String String::dedent() const {
int indent_stop = -1;
for (int i = 0; i < length(); i++) {
- CharType c = operator[](i);
+ char32_t c = operator[](i);
if (c == '\n') {
if (has_text) {
new_string += substr(indent_stop, i - indent_stop);
@@ -3218,7 +3684,7 @@ bool String::is_valid_identifier() const {
return false;
}
- const wchar_t *str = &operator[](0);
+ const char32_t *str = &operator[](0);
for (int i = 0; i < len; i++) {
if (i == 0) {
@@ -3237,36 +3703,14 @@ bool String::is_valid_identifier() const {
return true;
}
-//kind of poor should be rewritten properly
-
-String String::word_wrap(int p_chars_per_line) const {
- int from = 0;
- int last_space = 0;
- String ret;
- for (int i = 0; i < length(); i++) {
- if (i - from >= p_chars_per_line) {
- if (last_space == -1) {
- ret += substr(from, i - from + 1) + "\n";
- } else {
- ret += substr(from, last_space - from) + "\n";
- i = last_space; //rewind
- }
- from = i + 1;
- last_space = -1;
- } else if (operator[](i) == ' ' || operator[](i) == '\t') {
- last_space = i;
- } else if (operator[](i) == '\n') {
- ret += substr(from, i - from) + "\n";
- from = i + 1;
- last_space = -1;
- }
- }
-
- if (from < length()) {
- ret += substr(from, length());
+bool String::is_valid_string() const {
+ int l = length();
+ const char32_t *src = get_data();
+ bool valid = true;
+ for (int i = 0; i < l; i++) {
+ valid = valid && (src[i] < 0xd800 || (src[i] > 0xdfff && src[i] <= 0x10ffff));
}
-
- return ret;
+ return valid;
}
String String::http_escape() const {
@@ -3297,9 +3741,9 @@ String String::http_unescape() const {
String res;
for (int i = 0; i < length(); ++i) {
if (ord_at(i) == '%' && i + 2 < length()) {
- CharType ord1 = ord_at(i + 1);
+ char32_t ord1 = ord_at(i + 1);
if ((ord1 >= '0' && ord1 <= '9') || (ord1 >= 'A' && ord1 <= 'Z')) {
- CharType ord2 = ord_at(i + 2);
+ char32_t ord2 = ord_at(i + 2);
if ((ord2 >= '0' && ord2 <= '9') || (ord2 >= 'A' && ord2 <= 'Z')) {
char bytes[3] = { (char)ord1, (char)ord2, 0 };
res += (char)strtol(bytes, nullptr, 16);
@@ -3389,18 +3833,18 @@ for (int i=1;i<32;i++) {
return str;
}
-static _FORCE_INLINE_ int _xml_unescape(const CharType *p_src, int p_src_len, CharType *p_dst) {
+static _FORCE_INLINE_ int _xml_unescape(const char32_t *p_src, int p_src_len, char32_t *p_dst) {
int len = 0;
while (p_src_len) {
if (*p_src == '&') {
int eat = 0;
if (p_src_len >= 4 && p_src[1] == '#') {
- CharType c = 0;
+ char32_t c = 0;
for (int i = 2; i < p_src_len; i++) {
eat = i + 1;
- CharType ct = p_src[i];
+ char32_t ct = p_src[i];
if (ct == ';') {
break;
} else if (ct >= '0' && ct <= '9') {
@@ -3476,12 +3920,12 @@ static _FORCE_INLINE_ int _xml_unescape(const CharType *p_src, int p_src_len, Ch
String String::xml_unescape() const {
String str;
int l = length();
- int len = _xml_unescape(c_str(), l, nullptr);
+ int len = _xml_unescape(get_data(), l, nullptr);
if (len == 0) {
return String();
}
str.resize(len + 1);
- _xml_unescape(c_str(), l, str.ptrw());
+ _xml_unescape(get_data(), l, str.ptrw());
str[len] = 0;
return str;
}
@@ -3602,7 +4046,7 @@ bool String::is_valid_hex_number(bool p_with_prefix) const {
}
for (int i = from; i < len; i++) {
- CharType c = operator[](i);
+ char32_t c = operator[](i);
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
continue;
}
@@ -3917,7 +4361,7 @@ String String::percent_decode() const {
String String::property_name_encode() const {
// Escape and quote strings with extended ASCII or further Unicode characters
// as well as '"', '=' or ' ' (32)
- const CharType *cstr = c_str();
+ const char32_t *cstr = get_data();
for (int i = 0; cstr[i]; i++) {
if (cstr[i] == '=' || cstr[i] == '"' || cstr[i] < 33 || cstr[i] > 126) {
return "\"" + c_escape_multiline() + "\"";
@@ -3984,7 +4428,7 @@ String String::lpad(int min_length, const String &character) const {
// In case of an error, the string returned is the error description and "error" is true.
String String::sprintf(const Array &values, bool *error) const {
String formatted;
- CharType *self = (CharType *)c_str();
+ char32_t *self = (char32_t *)get_data();
bool in_format = false;
int value_index = 0;
int min_chars = 0;
@@ -3997,7 +4441,7 @@ String String::sprintf(const Array &values, bool *error) const {
*error = true;
for (; *self; self++) {
- const CharType c = *self;
+ const char32_t c = *self;
if (in_format) { // We have % - lets see what else we get.
switch (c) {
@@ -4134,9 +4578,11 @@ String String::sprintf(const Array &values, bool *error) const {
if (values[value_index].is_num()) {
int value = values[value_index];
if (value < 0) {
- return "unsigned byte integer is lower than maximum";
- } else if (value > 255) {
- return "unsigned byte integer is greater than maximum";
+ return "unsigned integer is lower than minimum";
+ } else if (value >= 0xd800 && value <= 0xdfff) {
+ return "unsigned integer is invalid Unicode character";
+ } else if (value > 0x10ffff) {
+ return "unsigned integer is greater than maximum";
}
str = chr(values[value_index]);
} else if (values[value_index].get_type() == Variant::STRING) {
diff --git a/core/ustring.h b/core/ustring.h
index 7a1c1a5232..1f8a5d7e7d 100644
--- a/core/ustring.h
+++ b/core/ustring.h
@@ -36,8 +36,13 @@
#include "core/typedefs.h"
#include "core/vector.h"
+/*************************************************************************/
+/* CharProxy */
+/*************************************************************************/
+
template <class T>
class CharProxy {
+ friend class Char16String;
friend class CharString;
friend class String;
@@ -71,6 +76,54 @@ public:
}
};
+/*************************************************************************/
+/* Char16String */
+/*************************************************************************/
+
+class Char16String {
+ CowData<char16_t> _cowdata;
+ static const char16_t _null;
+
+public:
+ _FORCE_INLINE_ char16_t *ptrw() { return _cowdata.ptrw(); }
+ _FORCE_INLINE_ const char16_t *ptr() const { return _cowdata.ptr(); }
+ _FORCE_INLINE_ int size() const { return _cowdata.size(); }
+ Error resize(int p_size) { return _cowdata.resize(p_size); }
+
+ _FORCE_INLINE_ char16_t get(int p_index) const { return _cowdata.get(p_index); }
+ _FORCE_INLINE_ void set(int p_index, const char16_t &p_elem) { _cowdata.set(p_index, p_elem); }
+ _FORCE_INLINE_ const char16_t &operator[](int p_index) const {
+ if (unlikely(p_index == _cowdata.size())) {
+ return _null;
+ }
+
+ return _cowdata.get(p_index);
+ }
+ _FORCE_INLINE_ CharProxy<char16_t> operator[](int p_index) { return CharProxy<char16_t>(p_index, _cowdata); }
+
+ _FORCE_INLINE_ Char16String() {}
+ _FORCE_INLINE_ Char16String(const Char16String &p_str) { _cowdata._ref(p_str._cowdata); }
+ _FORCE_INLINE_ Char16String &operator=(const Char16String &p_str) {
+ _cowdata._ref(p_str._cowdata);
+ return *this;
+ }
+ _FORCE_INLINE_ Char16String(const char16_t *p_cstr) { copy_from(p_cstr); }
+
+ Char16String &operator=(const char16_t *p_cstr);
+ bool operator<(const Char16String &p_right) const;
+ Char16String &operator+=(char16_t p_char);
+ int length() const { return size() ? size() - 1 : 0; }
+ const char16_t *get_data() const;
+ operator const char16_t *() const { return get_data(); };
+
+protected:
+ void copy_from(const char16_t *p_cstr);
+};
+
+/*************************************************************************/
+/* CharString */
+/*************************************************************************/
+
class CharString {
CowData<char> _cowdata;
static const char _null;
@@ -94,7 +147,7 @@ public:
_FORCE_INLINE_ CharString() {}
_FORCE_INLINE_ CharString(const CharString &p_str) { _cowdata._ref(p_str._cowdata); }
- _FORCE_INLINE_ CharString operator=(const CharString &p_str) {
+ _FORCE_INLINE_ CharString &operator=(const CharString &p_str) {
_cowdata._ref(p_str._cowdata);
return *this;
}
@@ -111,26 +164,35 @@ protected:
void copy_from(const char *p_cstr);
};
-typedef wchar_t CharType;
+/*************************************************************************/
+/* String */
+/*************************************************************************/
struct StrRange {
- const CharType *c_str;
+ const char32_t *c_str;
int len;
- StrRange(const CharType *p_c_str = nullptr, int p_len = 0) {
+ StrRange(const char32_t *p_c_str = nullptr, int p_len = 0) {
c_str = p_c_str;
len = p_len;
}
};
class String {
- CowData<CharType> _cowdata;
- static const CharType _null;
+ CowData<char32_t> _cowdata;
+ static const char32_t _null;
void copy_from(const char *p_cstr);
- void copy_from(const CharType *p_cstr, const int p_clip_to = -1);
- void copy_from(const CharType &p_char);
- void copy_from_unchecked(const CharType *p_char, const int p_length);
+ void copy_from(const char *p_cstr, const int p_clip_to);
+ void copy_from(const wchar_t *p_cstr);
+ void copy_from(const wchar_t *p_cstr, const int p_clip_to);
+ void copy_from(const char32_t *p_cstr);
+ void copy_from(const char32_t *p_cstr, const int p_clip_to);
+
+ void copy_from(const char32_t &p_char);
+
+ void copy_from_unchecked(const char32_t *p_char, const int p_length);
+
bool _base_is_subsequence_of(const String &p_string, bool case_insensitive) const;
int _count(const String &p_string, int p_from, int p_to, bool p_case_insensitive) const;
@@ -140,48 +202,56 @@ public:
npos = -1 ///<for "some" compatibility with std::string (npos is a huge value in std::string)
};
- _FORCE_INLINE_ CharType *ptrw() { return _cowdata.ptrw(); }
- _FORCE_INLINE_ const CharType *ptr() const { return _cowdata.ptr(); }
+ _FORCE_INLINE_ char32_t *ptrw() { return _cowdata.ptrw(); }
+ _FORCE_INLINE_ const char32_t *ptr() const { return _cowdata.ptr(); }
void remove(int p_index) { _cowdata.remove(p_index); }
_FORCE_INLINE_ void clear() { resize(0); }
- _FORCE_INLINE_ CharType get(int p_index) const { return _cowdata.get(p_index); }
- _FORCE_INLINE_ void set(int p_index, const CharType &p_elem) { _cowdata.set(p_index, p_elem); }
+ _FORCE_INLINE_ char32_t get(int p_index) const { return _cowdata.get(p_index); }
+ _FORCE_INLINE_ void set(int p_index, const char32_t &p_elem) { _cowdata.set(p_index, p_elem); }
_FORCE_INLINE_ int size() const { return _cowdata.size(); }
Error resize(int p_size) { return _cowdata.resize(p_size); }
- _FORCE_INLINE_ const CharType &operator[](int p_index) const {
+ _FORCE_INLINE_ const char32_t &operator[](int p_index) const {
if (unlikely(p_index == _cowdata.size())) {
return _null;
}
return _cowdata.get(p_index);
}
- _FORCE_INLINE_ CharProxy<CharType> operator[](int p_index) { return CharProxy<CharType>(p_index, _cowdata); }
+ _FORCE_INLINE_ CharProxy<char32_t> operator[](int p_index) { return CharProxy<char32_t>(p_index, _cowdata); }
bool operator==(const String &p_str) const;
bool operator!=(const String &p_str) const;
String operator+(const String &p_str) const;
- //String operator+(CharType p_char) const;
String &operator+=(const String &);
- String &operator+=(CharType p_char);
+ String &operator+=(char32_t p_char);
String &operator+=(const char *p_str);
- String &operator+=(const CharType *p_str);
+ String &operator+=(const wchar_t *p_str);
+ String &operator+=(const char32_t *p_str);
/* Compatibility Operators */
void operator=(const char *p_str);
- void operator=(const CharType *p_str);
+ void operator=(const wchar_t *p_str);
+ void operator=(const char32_t *p_str);
+
bool operator==(const char *p_str) const;
- bool operator==(const CharType *p_str) const;
+ bool operator==(const wchar_t *p_str) const;
+ bool operator==(const char32_t *p_str) const;
bool operator==(const StrRange &p_str_range) const;
+
bool operator!=(const char *p_str) const;
- bool operator!=(const CharType *p_str) const;
- bool operator<(const CharType *p_str) const;
+ bool operator!=(const wchar_t *p_str) const;
+ bool operator!=(const char32_t *p_str) const;
+
+ bool operator<(const char32_t *p_str) const;
bool operator<(const char *p_str) const;
+ bool operator<(const wchar_t *p_str) const;
+
bool operator<(const String &p_str) const;
bool operator<=(const String &p_str) const;
@@ -189,7 +259,7 @@ public:
signed char nocasecmp_to(const String &p_str) const;
signed char naturalnocasecmp_to(const String &p_str) const;
- const CharType *c_str() const;
+ const char32_t *get_data() const;
/* standard size stuff */
_FORCE_INLINE_ int length() const {
@@ -197,11 +267,13 @@ public:
return s ? (s - 1) : 0; // length does not include zero
}
+ bool is_valid_string() const;
+
/* complex helpers */
String substr(int p_from, int p_chars = -1) const;
int find(const String &p_str, int p_from = 0) const; ///< return <0 if failed
int find(const char *p_str, int p_from = 0) const; ///< return <0 if failed
- int find_char(const CharType &p_char, int p_from = 0) const; ///< return <0 if failed
+ int find_char(const char32_t &p_char, int p_from = 0) const; ///< return <0 if failed
int findn(const String &p_str, int p_from = 0) const; ///< return <0 if failed, case insensitive
int rfind(const String &p_str, int p_from = -1) const; ///< return <0 if failed
int rfindn(const String &p_str, int p_from = -1) const; ///< return <0 if failed, case insensitive
@@ -238,26 +310,31 @@ public:
static String num_real(double p_num);
static String num_int64(int64_t p_num, int base = 10, bool capitalize_hex = false);
static String num_uint64(uint64_t p_num, int base = 10, bool capitalize_hex = false);
- static String chr(CharType p_char);
+ static String chr(char32_t p_char);
static String md5(const uint8_t *p_md5);
static String hex_encode_buffer(const uint8_t *p_buffer, int p_len);
bool is_numeric() const;
- double to_float() const;
+ double to_float() const;
int64_t hex_to_int(bool p_with_prefix = true) const;
int64_t bin_to_int(bool p_with_prefix = true) const;
int64_t to_int() const;
+
static int64_t to_int(const char *p_str, int p_len = -1);
+ static int64_t to_int(const wchar_t *p_str, int p_len = -1);
+ static int64_t to_int(const char32_t *p_str, int p_len = -1, bool p_clamp = false);
+
static double to_float(const char *p_str);
- static double to_float(const CharType *p_str, const CharType **r_end = nullptr);
- static int64_t to_int(const CharType *p_str, int p_len = -1, bool p_clamp = false);
+ static double to_float(const wchar_t *p_str, const wchar_t **r_end = nullptr);
+ static double to_float(const char32_t *p_str, const char32_t **r_end = nullptr);
+
String capitalize() const;
String camelcase_to_underscore(bool lowercase = true) const;
String get_with_code_lines() const;
int get_slice_count(String p_splitter) const;
String get_slice(String p_splitter, int p_slice) const;
- String get_slicec(CharType p_splitter, int p_slice) const;
+ String get_slicec(char32_t p_splitter, int p_slice) const;
Vector<String> split(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const;
Vector<String> rsplit(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const;
@@ -267,10 +344,10 @@ public:
Vector<int> split_ints(const String &p_splitter, bool p_allow_empty = true) const;
Vector<int> split_ints_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const;
- String join(Vector<String> parts);
+ String join(Vector<String> parts) const;
- static CharType char_uppercase(CharType p_char);
- static CharType char_lowercase(CharType p_char);
+ static char32_t char_uppercase(char32_t p_char);
+ static char32_t char_lowercase(char32_t p_char);
String to_upper() const;
String to_lower() const;
@@ -287,7 +364,7 @@ public:
String get_extension() const;
String get_basename() const;
String plus_file(const String &p_file) const;
- CharType ord_at(int p_idx) const;
+ char32_t ord_at(int p_idx) const;
void erase(int p_pos, int p_chars);
@@ -296,8 +373,14 @@ public:
bool parse_utf8(const char *p_utf8, int p_len = -1); //return true on error
static String utf8(const char *p_utf8, int p_len = -1);
- static uint32_t hash(const CharType *p_cstr, int p_len); /* hash the string */
- static uint32_t hash(const CharType *p_cstr); /* hash the string */
+ Char16String utf16() const;
+ bool parse_utf16(const char16_t *p_utf16, int p_len = -1); //return true on error
+ static String utf16(const char16_t *p_utf16, int p_len = -1);
+
+ static uint32_t hash(const char32_t *p_cstr, int p_len); /* hash the string */
+ static uint32_t hash(const char32_t *p_cstr); /* hash the string */
+ static uint32_t hash(const wchar_t *p_cstr, int p_len); /* hash the string */
+ static uint32_t hash(const wchar_t *p_cstr); /* hash the string */
static uint32_t hash(const char *p_cstr, int p_len); /* hash the string */
static uint32_t hash(const char *p_cstr); /* hash the string */
uint32_t hash() const; /* hash the string */
@@ -348,24 +431,30 @@ public:
/**
* The constructors must not depend on other overloads
*/
- /* String(CharType p_char);*/
+ /* String(char32_t p_char);*/
_FORCE_INLINE_ String() {}
_FORCE_INLINE_ String(const String &p_str) { _cowdata._ref(p_str._cowdata); }
- String operator=(const String &p_str) {
+ String &operator=(const String &p_str) {
_cowdata._ref(p_str._cowdata);
return *this;
}
String(const char *p_str);
- String(const CharType *p_str, int p_clip_to_len = -1);
+ String(const wchar_t *p_str);
+ String(const char32_t *p_str);
+ String(const char *p_str, int p_clip_to_len);
+ String(const wchar_t *p_str, int p_clip_to_len);
+ String(const char32_t *p_str, int p_clip_to_len);
String(const StrRange &p_range);
};
bool operator==(const char *p_chr, const String &p_str);
+bool operator==(const wchar_t *p_chr, const String &p_str);
String operator+(const char *p_chr, const String &p_str);
-String operator+(CharType p_chr, const String &p_str);
+String operator+(const wchar_t *p_chr, const String &p_str);
+String operator+(char32_t p_chr, const String &p_str);
String itos(int64_t p_val);
String uitos(uint64_t p_val);
@@ -387,15 +476,18 @@ struct NaturalNoCaseComparator {
template <typename L, typename R>
_FORCE_INLINE_ bool is_str_less(const L *l_ptr, const R *r_ptr) {
while (true) {
- if (*l_ptr == 0 && *r_ptr == 0) {
+ const char32_t l = *l_ptr;
+ const char32_t r = *r_ptr;
+
+ if (l == 0 && r == 0) {
return false;
- } else if (*l_ptr == 0) {
+ } else if (l == 0) {
return true;
- } else if (*r_ptr == 0) {
+ } else if (r == 0) {
return false;
- } else if (*l_ptr < *r_ptr) {
+ } else if (l < r) {
return true;
- } else if (*l_ptr > *r_ptr) {
+ } else if (l > r) {
return false;
}
@@ -432,7 +524,7 @@ String DTRN(const String &p_text, const String &p_text_plural, int p_n, const St
String RTR(const String &p_text, const String &p_context = "");
String RTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context = "");
-bool is_symbol(CharType c);
+bool is_symbol(char32_t c);
bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end);
#endif // USTRING_H
diff --git a/core/variant.cpp b/core/variant.cpp
index c19ce79e64..181ced0f32 100644
--- a/core/variant.cpp
+++ b/core/variant.cpp
@@ -1558,7 +1558,7 @@ Variant::operator unsigned char() const {
}
}
-Variant::operator CharType() const {
+Variant::operator char32_t() const {
return operator unsigned int();
}
@@ -2445,7 +2445,7 @@ Variant::Variant(const char *const p_cstring) {
memnew_placement(_data._mem, String((const char *)p_cstring));
}
-Variant::Variant(const CharType *p_wstring) {
+Variant::Variant(const char32_t *p_wstring) {
type = STRING;
memnew_placement(_data._mem, String(p_wstring));
}
diff --git a/core/variant.h b/core/variant.h
index 50b7a21eda..112003a7ae 100644
--- a/core/variant.h
+++ b/core/variant.h
@@ -120,6 +120,7 @@ public:
private:
friend struct _VariantCall;
+ friend class VariantInternal;
// Variant takes 20 bytes when real_t is float, and 36 if double
// it only allocates extra memory for aabb/matrix.
@@ -245,7 +246,7 @@ public:
operator ObjectID() const;
- operator CharType() const;
+ operator char32_t() const;
operator float() const;
operator double() const;
operator String() const;
@@ -322,7 +323,7 @@ public:
Variant(const String &p_string);
Variant(const StringName &p_string);
Variant(const char *const p_cstring);
- Variant(const CharType *p_wstring);
+ Variant(const char32_t *p_wstring);
Variant(const Vector2 &p_vector2);
Variant(const Vector2i &p_vector2i);
Variant(const Rect2 &p_rect2);
diff --git a/core/variant_call.cpp b/core/variant_call.cpp
index 91af127d32..7a1fdbaafe 100644
--- a/core/variant_call.cpp
+++ b/core/variant_call.cpp
@@ -239,6 +239,7 @@ struct _VariantCall {
VCALL_LOCALMEM1R(String, casecmp_to);
VCALL_LOCALMEM1R(String, nocasecmp_to);
+ VCALL_LOCALMEM1R(String, naturalnocasecmp_to);
VCALL_LOCALMEM0R(String, length);
VCALL_LOCALMEM3R(String, count);
VCALL_LOCALMEM3R(String, countn);
@@ -311,6 +312,8 @@ struct _VariantCall {
VCALL_LOCALMEM0R(String, to_int);
VCALL_LOCALMEM0R(String, to_float);
VCALL_LOCALMEM0R(String, hex_to_int);
+ VCALL_LOCALMEM2R(String, lpad);
+ VCALL_LOCALMEM2R(String, rpad);
VCALL_LOCALMEM1R(String, pad_decimals);
VCALL_LOCALMEM1R(String, pad_zeros);
VCALL_LOCALMEM1R(String, trim_prefix);
@@ -350,6 +353,39 @@ struct _VariantCall {
r_ret = retval;
}
+ static void _call_String_to_utf16(Variant &r_ret, Variant &p_self, const Variant **p_args) {
+ String *s = reinterpret_cast<String *>(p_self._data._mem);
+ if (s->empty()) {
+ r_ret = PackedByteArray();
+ return;
+ }
+ Char16String charstr = s->utf16();
+
+ PackedByteArray retval;
+ size_t len = charstr.length() * 2;
+ retval.resize(len);
+ uint8_t *w = retval.ptrw();
+ copymem(w, (const void *)charstr.ptr(), len);
+
+ r_ret = retval;
+ }
+
+ static void _call_String_to_utf32(Variant &r_ret, Variant &p_self, const Variant **p_args) {
+ String *s = reinterpret_cast<String *>(p_self._data._mem);
+ if (s->empty()) {
+ r_ret = PackedByteArray();
+ return;
+ }
+
+ PackedByteArray retval;
+ size_t len = s->length() * 4;
+ retval.resize(len);
+ uint8_t *w = retval.ptrw();
+ copymem(w, (const void *)s->ptr(), len);
+
+ r_ret = retval;
+ }
+
VCALL_LOCALMEM1R(Vector2, distance_to);
VCALL_LOCALMEM1R(Vector2, distance_squared_to);
VCALL_LOCALMEM0R(Vector2, length);
@@ -618,6 +654,26 @@ struct _VariantCall {
r_ret = s;
}
+ static void _call_PackedByteArray_get_string_from_utf16(Variant &r_ret, Variant &p_self, const Variant **p_args) {
+ PackedByteArray *ba = reinterpret_cast<PackedByteArray *>(p_self._data._mem);
+ String s;
+ if (ba->size() > 0) {
+ const uint8_t *r = ba->ptr();
+ s.parse_utf16((const char16_t *)r, ba->size() / 2);
+ }
+ r_ret = s;
+ }
+
+ static void _call_PackedByteArray_get_string_from_utf32(Variant &r_ret, Variant &p_self, const Variant **p_args) {
+ PackedByteArray *ba = reinterpret_cast<PackedByteArray *>(p_self._data._mem);
+ String s;
+ if (ba->size() > 0) {
+ const uint8_t *r = ba->ptr();
+ s = String((const char32_t *)r, ba->size() / 4);
+ }
+ r_ret = s;
+ }
+
static void _call_PackedByteArray_compress(Variant &r_ret, Variant &p_self, const Variant **p_args) {
PackedByteArray *ba = reinterpret_cast<PackedByteArray *>(p_self._data._mem);
PackedByteArray compressed;
@@ -1789,6 +1845,7 @@ void register_variant_methods() {
/* STRING */
ADDFUNC1R(STRING, INT, String, casecmp_to, STRING, "to", varray());
ADDFUNC1R(STRING, INT, String, nocasecmp_to, STRING, "to", varray());
+ ADDFUNC1R(STRING, INT, String, naturalnocasecmp_to, STRING, "to", varray());
ADDFUNC0R(STRING, INT, String, length, varray());
ADDFUNC2R(STRING, STRING, String, substr, INT, "from", INT, "len", varray(-1));
@@ -1867,6 +1924,8 @@ void register_variant_methods() {
ADDFUNC0R(STRING, INT, String, to_int, varray());
ADDFUNC0R(STRING, FLOAT, String, to_float, varray());
ADDFUNC0R(STRING, INT, String, hex_to_int, varray());
+ ADDFUNC2R(STRING, STRING, String, lpad, INT, "min_length", STRING, "character", varray(" "));
+ ADDFUNC2R(STRING, STRING, String, rpad, INT, "min_length", STRING, "character", varray(" "));
ADDFUNC1R(STRING, STRING, String, pad_decimals, INT, "digits", varray());
ADDFUNC1R(STRING, STRING, String, pad_zeros, INT, "digits", varray());
ADDFUNC1R(STRING, STRING, String, trim_prefix, STRING, "prefix", varray());
@@ -1874,6 +1933,8 @@ void register_variant_methods() {
ADDFUNC0R(STRING, PACKED_BYTE_ARRAY, String, to_ascii, varray());
ADDFUNC0R(STRING, PACKED_BYTE_ARRAY, String, to_utf8, varray());
+ ADDFUNC0R(STRING, PACKED_BYTE_ARRAY, String, to_utf16, varray());
+ ADDFUNC0R(STRING, PACKED_BYTE_ARRAY, String, to_utf32, varray());
ADDFUNC0R(VECTOR2, FLOAT, Vector2, angle, varray());
ADDFUNC1R(VECTOR2, FLOAT, Vector2, angle_to, VECTOR2, "to", varray());
@@ -2109,6 +2170,8 @@ void register_variant_methods() {
ADDFUNC0R(PACKED_BYTE_ARRAY, STRING, PackedByteArray, get_string_from_ascii, varray());
ADDFUNC0R(PACKED_BYTE_ARRAY, STRING, PackedByteArray, get_string_from_utf8, varray());
+ ADDFUNC0R(PACKED_BYTE_ARRAY, STRING, PackedByteArray, get_string_from_utf16, varray());
+ ADDFUNC0R(PACKED_BYTE_ARRAY, STRING, PackedByteArray, get_string_from_utf32, varray());
ADDFUNC0R(PACKED_BYTE_ARRAY, STRING, PackedByteArray, hex_encode, varray());
ADDFUNC1R(PACKED_BYTE_ARRAY, PACKED_BYTE_ARRAY, PackedByteArray, compress, INT, "compression_mode", varray(0));
ADDFUNC2R(PACKED_BYTE_ARRAY, PACKED_BYTE_ARRAY, PackedByteArray, decompress, INT, "buffer_size", INT, "compression_mode", varray(0));
diff --git a/core/variant_internal.h b/core/variant_internal.h
new file mode 100644
index 0000000000..0e0a1e398f
--- /dev/null
+++ b/core/variant_internal.h
@@ -0,0 +1,118 @@
+/*************************************************************************/
+/* variant_internal.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef VARIANT_INTERNAL_H
+#define VARIANT_INTERNAL_H
+
+#include "variant.h"
+
+// For use when you want to access the internal pointer of a Variant directly.
+// Use with caution. You need to be sure that the type is correct.
+class VariantInternal {
+public:
+ // Set type.
+ _FORCE_INLINE_ static void initialize(Variant *v, Variant::Type p_type) { v->type = p_type; }
+
+ // Atomic types.
+ _FORCE_INLINE_ static bool *get_bool(Variant *v) { return &v->_data._bool; }
+ _FORCE_INLINE_ static const bool *get_bool(const Variant *v) { return &v->_data._bool; }
+ _FORCE_INLINE_ static int64_t *get_int(Variant *v) { return &v->_data._int; }
+ _FORCE_INLINE_ static const int64_t *get_int(const Variant *v) { return &v->_data._int; }
+ _FORCE_INLINE_ static double *get_float(Variant *v) { return &v->_data._float; }
+ _FORCE_INLINE_ static const double *get_float(const Variant *v) { return &v->_data._float; }
+ _FORCE_INLINE_ static String *get_string(Variant *v) { return reinterpret_cast<String *>(v->_data._mem); }
+ _FORCE_INLINE_ static const String *get_string(const Variant *v) { return reinterpret_cast<const String *>(v->_data._mem); }
+
+ // Math types.
+ _FORCE_INLINE_ static Vector2 *get_vector2(Variant *v) { return reinterpret_cast<Vector2 *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Vector2 *get_vector2(const Variant *v) { return reinterpret_cast<const Vector2 *>(v->_data._mem); }
+ _FORCE_INLINE_ static Vector2i *get_vector2i(Variant *v) { return reinterpret_cast<Vector2i *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Vector2i *get_vector2i(const Variant *v) { return reinterpret_cast<const Vector2i *>(v->_data._mem); }
+ _FORCE_INLINE_ static Rect2 *get_rect2(Variant *v) { return reinterpret_cast<Rect2 *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Rect2 *get_rect2(const Variant *v) { return reinterpret_cast<const Rect2 *>(v->_data._mem); }
+ _FORCE_INLINE_ static Rect2i *get_rect2i(Variant *v) { return reinterpret_cast<Rect2i *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Rect2i *get_rect2i(const Variant *v) { return reinterpret_cast<const Rect2i *>(v->_data._mem); }
+ _FORCE_INLINE_ static Vector3 *get_vector3(Variant *v) { return reinterpret_cast<Vector3 *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Vector3 *get_vector3(const Variant *v) { return reinterpret_cast<const Vector3 *>(v->_data._mem); }
+ _FORCE_INLINE_ static Vector3i *get_vector3i(Variant *v) { return reinterpret_cast<Vector3i *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Vector3i *get_vector3i(const Variant *v) { return reinterpret_cast<const Vector3i *>(v->_data._mem); }
+ _FORCE_INLINE_ static Transform2D *get_transform2d(Variant *v) { return v->_data._transform2d; }
+ _FORCE_INLINE_ static const Transform2D *get_transform2d(const Variant *v) { return v->_data._transform2d; }
+ _FORCE_INLINE_ static Plane *get_plane(Variant *v) { return reinterpret_cast<Plane *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Plane *get_plane(const Variant *v) { return reinterpret_cast<const Plane *>(v->_data._mem); }
+ _FORCE_INLINE_ static Quat *get_quat(Variant *v) { return reinterpret_cast<Quat *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Quat *get_quat(const Variant *v) { return reinterpret_cast<const Quat *>(v->_data._mem); }
+ _FORCE_INLINE_ static ::AABB *get_aabb(Variant *v) { return v->_data._aabb; }
+ _FORCE_INLINE_ static const ::AABB *get_aabb(const Variant *v) { return v->_data._aabb; }
+ _FORCE_INLINE_ static Basis *get_basis(Variant *v) { return v->_data._basis; }
+ _FORCE_INLINE_ static const Basis *get_basis(const Variant *v) { return v->_data._basis; }
+ _FORCE_INLINE_ static Transform *get_transform(Variant *v) { return v->_data._transform; }
+ _FORCE_INLINE_ static const Transform *get_transform(const Variant *v) { return v->_data._transform; }
+
+ // Misc types.
+ _FORCE_INLINE_ static Color *get_color(Variant *v) { return reinterpret_cast<Color *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Color *get_color(const Variant *v) { return reinterpret_cast<const Color *>(v->_data._mem); }
+ _FORCE_INLINE_ static StringName *get_string_name(Variant *v) { return reinterpret_cast<StringName *>(v->_data._mem); }
+ _FORCE_INLINE_ static const StringName *get_string_name(const Variant *v) { return reinterpret_cast<const StringName *>(v->_data._mem); }
+ _FORCE_INLINE_ static NodePath *get_node_path(Variant *v) { return reinterpret_cast<NodePath *>(v->_data._mem); }
+ _FORCE_INLINE_ static const NodePath *get_node_path(const Variant *v) { return reinterpret_cast<const NodePath *>(v->_data._mem); }
+ _FORCE_INLINE_ static RID *get_rid(Variant *v) { return reinterpret_cast<RID *>(v->_data._mem); }
+ _FORCE_INLINE_ static const RID *get_rid(const Variant *v) { return reinterpret_cast<const RID *>(v->_data._mem); }
+ _FORCE_INLINE_ static Callable *get_callable(Variant *v) { return reinterpret_cast<Callable *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Callable *get_callable(const Variant *v) { return reinterpret_cast<const Callable *>(v->_data._mem); }
+ _FORCE_INLINE_ static Signal *get_signal(Variant *v) { return reinterpret_cast<Signal *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Signal *get_signal(const Variant *v) { return reinterpret_cast<const Signal *>(v->_data._mem); }
+ _FORCE_INLINE_ static Dictionary *get_dictionary(Variant *v) { return reinterpret_cast<Dictionary *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Dictionary *get_dictionary(const Variant *v) { return reinterpret_cast<const Dictionary *>(v->_data._mem); }
+ _FORCE_INLINE_ static Array *get_array(Variant *v) { return reinterpret_cast<Array *>(v->_data._mem); }
+ _FORCE_INLINE_ static const Array *get_array(const Variant *v) { return reinterpret_cast<const Array *>(v->_data._mem); }
+
+ // Typed arrays.
+ _FORCE_INLINE_ static PackedByteArray *get_byte_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<uint8_t> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedByteArray *get_byte_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<uint8_t> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedInt32Array *get_int32_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<int32_t> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedInt32Array *get_int32_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<int32_t> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedInt64Array *get_int64_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<int64_t> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedInt64Array *get_int64_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<int64_t> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedFloat32Array *get_float32_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<float> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedFloat32Array *get_float32_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<float> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedFloat64Array *get_float64_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<double> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedFloat64Array *get_float64_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<double> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedStringArray *get_string_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<String> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedStringArray *get_string_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<String> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedVector2Array *get_vector2_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<Vector2> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedVector2Array *get_vector2_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<Vector2> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedVector3Array *get_vector3_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<Vector3> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedVector3Array *get_vector3_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<Vector3> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static PackedColorArray *get_color_array(Variant *v) { return &static_cast<Variant::PackedArrayRef<Color> *>(v->_data.packed_array)->array; }
+ _FORCE_INLINE_ static const PackedColorArray *get_color_array(const Variant *v) { return &static_cast<const Variant::PackedArrayRef<Color> *>(v->_data.packed_array)->array; }
+};
+
+#endif // VARIANT_INTERNAL_H
diff --git a/core/variant_op.cpp b/core/variant_op.cpp
index 0c9a4a992a..95b488230d 100644
--- a/core/variant_op.cpp
+++ b/core/variant_op.cpp
@@ -118,32 +118,32 @@
/* clang-format on */
-#define CASES(PREFIX) static const void *switch_table_##PREFIX[25][Variant::VARIANT_MAX] = { \
- TYPES(PREFIX, OP_EQUAL), \
- TYPES(PREFIX, OP_NOT_EQUAL), \
- TYPES(PREFIX, OP_LESS), \
- TYPES(PREFIX, OP_LESS_EQUAL), \
- TYPES(PREFIX, OP_GREATER), \
- TYPES(PREFIX, OP_GREATER_EQUAL), \
- TYPES(PREFIX, OP_ADD), \
- TYPES(PREFIX, OP_SUBTRACT), \
- TYPES(PREFIX, OP_MULTIPLY), \
- TYPES(PREFIX, OP_DIVIDE), \
- TYPES(PREFIX, OP_NEGATE), \
- TYPES(PREFIX, OP_POSITIVE), \
- TYPES(PREFIX, OP_MODULE), \
- TYPES(PREFIX, OP_STRING_CONCAT), \
- TYPES(PREFIX, OP_SHIFT_LEFT), \
- TYPES(PREFIX, OP_SHIFT_RIGHT), \
- TYPES(PREFIX, OP_BIT_AND), \
- TYPES(PREFIX, OP_BIT_OR), \
- TYPES(PREFIX, OP_BIT_XOR), \
- TYPES(PREFIX, OP_BIT_NEGATE), \
- TYPES(PREFIX, OP_AND), \
- TYPES(PREFIX, OP_OR), \
- TYPES(PREFIX, OP_XOR), \
- TYPES(PREFIX, OP_NOT), \
- TYPES(PREFIX, OP_IN), \
+#define CASES(PREFIX) static const void *switch_table_##PREFIX[Variant::OP_MAX][Variant::VARIANT_MAX] = { \
+ TYPES(PREFIX, OP_EQUAL), \
+ TYPES(PREFIX, OP_NOT_EQUAL), \
+ TYPES(PREFIX, OP_LESS), \
+ TYPES(PREFIX, OP_LESS_EQUAL), \
+ TYPES(PREFIX, OP_GREATER), \
+ TYPES(PREFIX, OP_GREATER_EQUAL), \
+ TYPES(PREFIX, OP_ADD), \
+ TYPES(PREFIX, OP_SUBTRACT), \
+ TYPES(PREFIX, OP_MULTIPLY), \
+ TYPES(PREFIX, OP_DIVIDE), \
+ TYPES(PREFIX, OP_NEGATE), \
+ TYPES(PREFIX, OP_POSITIVE), \
+ TYPES(PREFIX, OP_MODULE), \
+ TYPES(PREFIX, OP_STRING_CONCAT), \
+ TYPES(PREFIX, OP_SHIFT_LEFT), \
+ TYPES(PREFIX, OP_SHIFT_RIGHT), \
+ TYPES(PREFIX, OP_BIT_AND), \
+ TYPES(PREFIX, OP_BIT_OR), \
+ TYPES(PREFIX, OP_BIT_XOR), \
+ TYPES(PREFIX, OP_BIT_NEGATE), \
+ TYPES(PREFIX, OP_AND), \
+ TYPES(PREFIX, OP_OR), \
+ TYPES(PREFIX, OP_XOR), \
+ TYPES(PREFIX, OP_NOT), \
+ TYPES(PREFIX, OP_IN), \
}
#define SWITCH(PREFIX, op, val) goto *switch_table_##PREFIX[op][val];
@@ -4215,7 +4215,7 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant &
int split = csize / 2;
for (int i = 0; i < csize; i++) {
- CharType chr = ' ';
+ char32_t chr = ' ';
if (i < split) {
if (i < sa.length()) {
diff --git a/core/variant_parser.cpp b/core/variant_parser.cpp
index 74f4f32c0e..3c4fed68fb 100644
--- a/core/variant_parser.cpp
+++ b/core/variant_parser.cpp
@@ -35,7 +35,7 @@
#include "core/os/keyboard.h"
#include "core/string_buffer.h"
-CharType VariantParser::StreamFile::get_char() {
+char32_t VariantParser::StreamFile::get_char() {
return f->get_8();
}
@@ -47,7 +47,7 @@ bool VariantParser::StreamFile::is_eof() const {
return f->eof_reached();
}
-CharType VariantParser::StreamString::get_char() {
+char32_t VariantParser::StreamString::get_char() {
if (pos > s.length()) {
return 0;
} else if (pos == s.length()) {
@@ -94,7 +94,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
bool string_name = false;
while (true) {
- CharType cchar;
+ char32_t cchar;
if (p_stream->saved) {
cchar = p_stream->saved;
p_stream->saved = 0;
@@ -145,7 +145,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
}
case ';': {
while (true) {
- CharType ch = p_stream->get_char();
+ char32_t ch = p_stream->get_char();
if (p_stream->is_eof()) {
r_token.type = TK_EOF;
return OK;
@@ -173,7 +173,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
StringBuffer<> color_str;
color_str += '#';
while (true) {
- CharType ch = p_stream->get_char();
+ char32_t ch = p_stream->get_char();
if (p_stream->is_eof()) {
r_token.type = TK_EOF;
return OK;
@@ -204,7 +204,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
case '"': {
String str;
while (true) {
- CharType ch = p_stream->get_char();
+ char32_t ch = p_stream->get_char();
if (ch == 0) {
r_err_str = "Unterminated String";
@@ -214,13 +214,13 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
break;
} else if (ch == '\\') {
//escaped characters...
- CharType next = p_stream->get_char();
+ char32_t next = p_stream->get_char();
if (next == 0) {
r_err_str = "Unterminated String";
r_token.type = TK_ERROR;
return ERR_PARSE_ERROR;
}
- CharType res = 0;
+ char32_t res = 0;
switch (next) {
case 'b':
@@ -241,7 +241,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
case 'u': {
//hex number
for (int j = 0; j < 4; j++) {
- CharType c = p_stream->get_char();
+ char32_t c = p_stream->get_char();
if (c == 0) {
r_err_str = "Unterminated String";
r_token.type = TK_ERROR;
@@ -252,7 +252,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
r_token.type = TK_ERROR;
return ERR_PARSE_ERROR;
}
- CharType v;
+ char32_t v;
if (c >= '0' && c <= '9') {
v = c - '0';
} else if (c >= 'a' && c <= 'f') {
@@ -321,7 +321,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
cchar = p_stream->get_char();
}
- CharType c = cchar;
+ char32_t c = cchar;
bool exp_sign = false;
bool exp_beg = false;
bool is_float = false;
@@ -421,7 +421,7 @@ Error VariantParser::_parse_enginecfg(Stream *p_stream, Vector<String> &strings,
String accum;
while (true) {
- CharType c = p_stream->get_char();
+ char32_t c = p_stream->get_char();
if (p_stream->is_eof()) {
r_err_str = "Unexpected EOF while parsing old-style project.godot construct";
@@ -1206,7 +1206,7 @@ Error VariantParser::_parse_tag(Token &token, Stream *p_stream, int &line, Strin
r_tag.fields.clear();
while (true) {
- CharType c = p_stream->get_char();
+ char32_t c = p_stream->get_char();
if (p_stream->is_eof()) {
r_err_str = "Unexpected EOF while parsing simple tag";
return ERR_PARSE_ERROR;
@@ -1305,7 +1305,7 @@ Error VariantParser::parse_tag_assign_eof(Stream *p_stream, int &line, String &r
String what;
while (true) {
- CharType c;
+ char32_t c;
if (p_stream->saved) {
c = p_stream->saved;
p_stream->saved = 0;
@@ -1320,7 +1320,7 @@ Error VariantParser::parse_tag_assign_eof(Stream *p_stream, int &line, String &r
if (c == ';') { //comment
while (true) {
- CharType ch = p_stream->get_char();
+ char32_t ch = p_stream->get_char();
if (p_stream->is_eof()) {
return ERR_FILE_EOF;
}
diff --git a/core/variant_parser.h b/core/variant_parser.h
index b55d7b2df0..12329e2db6 100644
--- a/core/variant_parser.h
+++ b/core/variant_parser.h
@@ -38,11 +38,11 @@
class VariantParser {
public:
struct Stream {
- virtual CharType get_char() = 0;
+ virtual char32_t get_char() = 0;
virtual bool is_utf8() const = 0;
virtual bool is_eof() const = 0;
- CharType saved = 0;
+ char32_t saved = 0;
Stream() {}
virtual ~Stream() {}
@@ -51,7 +51,7 @@ public:
struct StreamFile : public Stream {
FileAccess *f = nullptr;
- virtual CharType get_char();
+ virtual char32_t get_char();
virtual bool is_utf8() const;
virtual bool is_eof() const;
@@ -62,7 +62,7 @@ public:
String s;
int pos = 0;
- virtual CharType get_char();
+ virtual char32_t get_char();
virtual bool is_utf8() const;
virtual bool is_eof() const;
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 7f7df33471..2b1770f12b 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -27,6 +27,9 @@
<member name="Engine" type="Engine" setter="" getter="">
The [Engine] singleton.
</member>
+ <member name="EngineDebugger" type="EngineDebugger" setter="" getter="">
+ The [EngineDebugger] singleton.
+ </member>
<member name="Geometry2D" type="Geometry2D" setter="" getter="">
The [Geometry2D] singleton.
</member>
@@ -353,16 +356,16 @@
Right Direction key.
</constant>
<constant name="KEY_BACK" value="16777280" enum="KeyList">
- Back key.
+ Media back key. Not to be confused with the Back button on an Android device.
</constant>
<constant name="KEY_FORWARD" value="16777281" enum="KeyList">
- Forward key.
+ Media forward key.
</constant>
<constant name="KEY_STOP" value="16777282" enum="KeyList">
- Stop key.
+ Media stop key.
</constant>
<constant name="KEY_REFRESH" value="16777283" enum="KeyList">
- Refresh key.
+ Media refresh key.
</constant>
<constant name="KEY_VOLUMEDOWN" value="16777284" enum="KeyList">
Volume down key.
diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml
index ae80abc5d2..cbc04ca672 100644
--- a/doc/classes/AABB.xml
+++ b/doc/classes/AABB.xml
@@ -7,7 +7,7 @@
AABB consists of a position, a size, and several utility functions. It is typically used for fast overlap tests.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
+ <link title="Math tutorial index">https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
</tutorials>
<methods>
<method name="AABB">
diff --git a/doc/classes/AnimatedSprite2D.xml b/doc/classes/AnimatedSprite2D.xml
index 7a992d0c03..e23a4fe9f8 100644
--- a/doc/classes/AnimatedSprite2D.xml
+++ b/doc/classes/AnimatedSprite2D.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
Animations are created using a [SpriteFrames] resource, which can be configured in the editor via the SpriteFrames panel.
+ [b]Note:[/b] You can associate a set of normal or specular maps by creating additional [SpriteFrames] resources with a [code]_normal[/code] or [code]_specular[/code] suffix. For example, having 3 [SpriteFrames] resources [code]run[/code], [code]run_normal[/code], and [code]run_specular[/code] will make it so the [code]run[/code] animation uses normal and specular maps.
</description>
<tutorials>
<link title="2D Sprite animation">https://docs.godotengine.org/en/latest/tutorials/2d/2d_sprite_animation.html</link>
diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml
index 68f0a630ef..0a2925e6d5 100644
--- a/doc/classes/Animation.xml
+++ b/doc/classes/Animation.xml
@@ -17,7 +17,7 @@
Animations are just data containers, and must be added to nodes such as an [AnimationPlayer] to be played back. Animation tracks have different types, each with its own set of dedicated methods. Check [enum TrackType] to see available types.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/index.html</link>
+ <link title="Animation tutorial index">https://docs.godotengine.org/en/latest/tutorials/animation/index.html</link>
</tutorials>
<methods>
<method name="add_track">
diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml
index 3d6ebd5934..8204b456d9 100644
--- a/doc/classes/AnimationNode.xml
+++ b/doc/classes/AnimationNode.xml
@@ -8,7 +8,7 @@
Inherit this when creating nodes mainly for use in [AnimationNodeBlendTree], otherwise [AnimationRootNode] should be used instead.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
+ <link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
</tutorials>
<methods>
<method name="add_input">
diff --git a/doc/classes/AnimationNodeAdd2.xml b/doc/classes/AnimationNodeAdd2.xml
index 48983a624e..63127ade9a 100644
--- a/doc/classes/AnimationNodeAdd2.xml
+++ b/doc/classes/AnimationNodeAdd2.xml
@@ -7,7 +7,7 @@
A resource to add to an [AnimationNodeBlendTree]. Blends two animations additively based on an amount value in the [code][0.0, 1.0][/code] range.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
+ <link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/AnimationNodeAdd3.xml b/doc/classes/AnimationNodeAdd3.xml
index 1bfebc91fc..94a6ae4221 100644
--- a/doc/classes/AnimationNodeAdd3.xml
+++ b/doc/classes/AnimationNodeAdd3.xml
@@ -11,7 +11,7 @@
- A +add animation to blend with when the blend amount is in the [code][0.0, 1.0][/code] range
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
+ <link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/AnimationNodeAnimation.xml b/doc/classes/AnimationNodeAnimation.xml
index ab44148c15..d8ac5413fd 100644
--- a/doc/classes/AnimationNodeAnimation.xml
+++ b/doc/classes/AnimationNodeAnimation.xml
@@ -7,7 +7,7 @@
A resource to add to an [AnimationNodeBlendTree]. Only features one output set using the [member animation] property. Use it as an input for [AnimationNode] that blend animations together.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
+ <link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/AnimationNodeBlend2.xml b/doc/classes/AnimationNodeBlend2.xml
index 2b56167225..e2cd12e685 100644
--- a/doc/classes/AnimationNodeBlend2.xml
+++ b/doc/classes/AnimationNodeBlend2.xml
@@ -7,7 +7,7 @@
A resource to add to an [AnimationNodeBlendTree]. Blends two animations linearly based on an amount value in the [code][0.0, 1.0][/code] range.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
+ <link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/AnimationNodeBlend3.xml b/doc/classes/AnimationNodeBlend3.xml
index 5a306a225d..7c81b37663 100644
--- a/doc/classes/AnimationNodeBlend3.xml
+++ b/doc/classes/AnimationNodeBlend3.xml
@@ -11,7 +11,7 @@
- A +blend animation to blend with when the blend amount is in the [code][0.0, 1.0][/code] range
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
+ <link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/AnimationNodeBlendSpace1D.xml b/doc/classes/AnimationNodeBlendSpace1D.xml
index 6e82f0afb7..263b59910b 100644
--- a/doc/classes/AnimationNodeBlendSpace1D.xml
+++ b/doc/classes/AnimationNodeBlendSpace1D.xml
@@ -10,7 +10,7 @@
You can set the extents of the axis using the [member min_space] and [member max_space].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
+ <link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
</tutorials>
<methods>
<method name="add_blend_point">
diff --git a/doc/classes/AnimationNodeBlendSpace2D.xml b/doc/classes/AnimationNodeBlendSpace2D.xml
index f8680ba8ec..460c11cc5e 100644
--- a/doc/classes/AnimationNodeBlendSpace2D.xml
+++ b/doc/classes/AnimationNodeBlendSpace2D.xml
@@ -9,7 +9,7 @@
You can add vertices to the blend space with [method add_blend_point] and automatically triangulate it by setting [member auto_triangles] to [code]true[/code]. Otherwise, use [method add_triangle] and [method remove_triangle] to create up the blend space by hand.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
+ <link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
</tutorials>
<methods>
<method name="add_blend_point">
diff --git a/doc/classes/AnimationNodeBlendTree.xml b/doc/classes/AnimationNodeBlendTree.xml
index 4a34d75ff9..8f87ce453f 100644
--- a/doc/classes/AnimationNodeBlendTree.xml
+++ b/doc/classes/AnimationNodeBlendTree.xml
@@ -7,7 +7,7 @@
This node may contain a sub-tree of any other blend type nodes, such as mix, blend2, blend3, one shot, etc. This is one of the most commonly used roots.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
+ <link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
</tutorials>
<methods>
<method name="add_node">
diff --git a/doc/classes/AnimationNodeOneShot.xml b/doc/classes/AnimationNodeOneShot.xml
index 4ba0b82df6..d5793e5839 100644
--- a/doc/classes/AnimationNodeOneShot.xml
+++ b/doc/classes/AnimationNodeOneShot.xml
@@ -7,7 +7,7 @@
A resource to add to an [AnimationNodeBlendTree]. This node will execute a sub-animation and return once it finishes. Blend times for fading in and out can be customized, as well as filters.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
+ <link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
</tutorials>
<methods>
<method name="get_mix_mode" qualifiers="const">
diff --git a/doc/classes/AnimationNodeOutput.xml b/doc/classes/AnimationNodeOutput.xml
index 38b05eb650..7640f4dcfa 100644
--- a/doc/classes/AnimationNodeOutput.xml
+++ b/doc/classes/AnimationNodeOutput.xml
@@ -6,7 +6,7 @@
<description>
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
+ <link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/AnimationNodeStateMachine.xml b/doc/classes/AnimationNodeStateMachine.xml
index 3b351a3345..9ea83d2c5e 100644
--- a/doc/classes/AnimationNodeStateMachine.xml
+++ b/doc/classes/AnimationNodeStateMachine.xml
@@ -12,7 +12,7 @@
[/codeblock]
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
+ <link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
</tutorials>
<methods>
<method name="add_node">
diff --git a/doc/classes/AnimationNodeStateMachinePlayback.xml b/doc/classes/AnimationNodeStateMachinePlayback.xml
index f4b89a5086..fec68d5b74 100644
--- a/doc/classes/AnimationNodeStateMachinePlayback.xml
+++ b/doc/classes/AnimationNodeStateMachinePlayback.xml
@@ -12,7 +12,7 @@
[/codeblock]
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
+ <link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
</tutorials>
<methods>
<method name="get_current_node" qualifiers="const">
diff --git a/doc/classes/AnimationNodeStateMachineTransition.xml b/doc/classes/AnimationNodeStateMachineTransition.xml
index f0b7cc4099..fe0154acad 100644
--- a/doc/classes/AnimationNodeStateMachineTransition.xml
+++ b/doc/classes/AnimationNodeStateMachineTransition.xml
@@ -5,7 +5,7 @@
<description>
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
+ <link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/AnimationNodeTimeScale.xml b/doc/classes/AnimationNodeTimeScale.xml
index 5c2e6cb692..334fdb0b95 100644
--- a/doc/classes/AnimationNodeTimeScale.xml
+++ b/doc/classes/AnimationNodeTimeScale.xml
@@ -7,7 +7,7 @@
Allows scaling the speed of the animation (or reversing it) in any children nodes. Setting it to 0 will pause the animation.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
+ <link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/AnimationNodeTimeSeek.xml b/doc/classes/AnimationNodeTimeSeek.xml
index 0fef106da5..eb5335c792 100644
--- a/doc/classes/AnimationNodeTimeSeek.xml
+++ b/doc/classes/AnimationNodeTimeSeek.xml
@@ -7,7 +7,7 @@
This node can be used to cause a seek command to happen to any sub-children of the graph. After setting the time, this value returns to -1.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
+ <link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/AnimationNodeTransition.xml b/doc/classes/AnimationNodeTransition.xml
index 11250c5b17..8338f0d39a 100644
--- a/doc/classes/AnimationNodeTransition.xml
+++ b/doc/classes/AnimationNodeTransition.xml
@@ -7,7 +7,7 @@
Simple state machine for cases which don't require a more advanced [AnimationNodeStateMachine]. Animations can be connected to the inputs and transition times can be specified.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
+ <link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
</tutorials>
<methods>
<method name="get_input_caption" qualifiers="const">
diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml
index 6267a5a0a9..8396cdb6cf 100644
--- a/doc/classes/AnimationPlayer.xml
+++ b/doc/classes/AnimationPlayer.xml
@@ -9,9 +9,9 @@
Updating the target properties of animations occurs at process time.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/getting_started/step_by_step/animations.html</link>
+ <link title="Animations">https://docs.godotengine.org/en/latest/getting_started/step_by_step/animations.html</link>
<link title="2D Sprite animation">https://docs.godotengine.org/en/latest/tutorials/2d/2d_sprite_animation.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/index.html</link>
+ <link title="Animation tutorial index">https://docs.godotengine.org/en/latest/tutorials/animation/index.html</link>
</tutorials>
<methods>
<method name="add_animation">
@@ -236,7 +236,8 @@
The name of the animation to play when the scene loads.
</member>
<member name="current_animation" type="String" setter="set_current_animation" getter="get_current_animation" default="&quot;&quot;">
- The name of the current animation, "" if not playing anything. When being set, does not restart the animation. See also [method play].
+ The name of the currently playing animation. If no animation is playing, the property's value is an empty string. Changing this value does not restart the animation. See [method play] for more information on playing animations.
+ [b]Note[/b]: while this property appears in the inspector, it's not meant to be edited and it's not saved in the scene. This property is mainly used to get the currently playing animation, and internally for animation playback tracks. For more information, see [Animation].
</member>
<member name="current_animation_length" type="float" setter="" getter="get_current_animation_length">
The length (in seconds) of the currently being played animation.
diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml
index dd04f4ce3f..cc8e83f509 100644
--- a/doc/classes/AnimationTree.xml
+++ b/doc/classes/AnimationTree.xml
@@ -7,8 +7,8 @@
Note: When linked with an [AnimationPlayer], several properties and methods of the corresponding [AnimationPlayer] will not function as expected. Playback and transitions should be handled using only the [AnimationTree] and its constituent [AnimationNode](s). The [AnimationPlayer] node should be used solely for adding, deleting, and editing animations.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
- <link>https://github.com/godotengine/tps-demo</link>
+ <link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link>
+ <link title="Third-person shooter demo code repository">https://github.com/godotengine/tps-demo</link>
</tutorials>
<methods>
<method name="advance">
diff --git a/doc/classes/Area2D.xml b/doc/classes/Area2D.xml
index 4190cbe6b9..e98c0af0d9 100644
--- a/doc/classes/Area2D.xml
+++ b/doc/classes/Area2D.xml
@@ -7,7 +7,7 @@
2D area that detects [CollisionObject2D] nodes overlapping, entering, or exiting. Can also alter or override local physics parameters (gravity, damping).
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/using_area_2d.html</link>
+ <link title="Using Area2D">https://docs.godotengine.org/en/latest/tutorials/physics/using_area_2d.html</link>
</tutorials>
<methods>
<method name="get_collision_layer_bit" qualifiers="const">
@@ -97,10 +97,10 @@
If [code]true[/code], the area's audio bus overrides the default audio bus.
</member>
<member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
- The area's physics layer(s). Collidable objects can exist in any of 32 different layers. A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. See also [member collision_mask].
+ The area's physics layer(s). Collidable objects can exist in any of 32 different layers. A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. See also [member collision_mask]. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this area scans to determine collision detection.
+ The physics layers this area scans to determine collision detection. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="gravity" type="float" setter="set_gravity" getter="get_gravity" default="98.0">
The area's gravity intensity (ranges from -1024 to 1024). This value multiplies the gravity vector. This is useful to alter the force of gravity without altering its direction.
diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml
index a94cecd879..ad9eff3a64 100644
--- a/doc/classes/Area3D.xml
+++ b/doc/classes/Area3D.xml
@@ -96,10 +96,10 @@
If [code]true[/code], the area's audio bus overrides the default audio bus.
</member>
<member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
- The area's physics layer(s). Collidable objects can exist in any of 32 different layers. A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. See also [member collision_mask].
+ The area's physics layer(s). Collidable objects can exist in any of 32 different layers. A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. See also [member collision_mask]. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this area scans to determine collision detection.
+ The physics layers this area scans to determine collision detection. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="gravity" type="float" setter="set_gravity" getter="get_gravity" default="9.8">
The area's gravity intensity (ranges from -1024 to 1024). This value multiplies the gravity vector. This is useful to alter the force of gravity without altering its direction.
diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml
index b45716544a..4ec39ecc2f 100644
--- a/doc/classes/ArrayMesh.xml
+++ b/doc/classes/ArrayMesh.xml
@@ -26,7 +26,7 @@
[b]Note:[/b] Godot uses clockwise [url=https://learnopengl.com/Advanced-OpenGL/Face-culling]winding order[/url] for front faces of triangle primitive modes.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/content/procedural_geometry/arraymesh.html</link>
+ <link title="Procedural geometry using the ArrayMesh">https://docs.godotengine.org/en/latest/tutorials/content/procedural_geometry/arraymesh.html</link>
</tutorials>
<methods>
<method name="add_blend_shape">
diff --git a/doc/classes/AudioEffectRecord.xml b/doc/classes/AudioEffectRecord.xml
index a217342d98..6617d16290 100644
--- a/doc/classes/AudioEffectRecord.xml
+++ b/doc/classes/AudioEffectRecord.xml
@@ -7,7 +7,7 @@
Allows the user to record sound from a microphone. It sets and gets the format in which the audio file will be recorded (8-bit, 16-bit, or compressed). It checks whether or not the recording is active, and if it is, records the sound. It then returns the recorded sample.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/audio/recording_with_microphone.html</link>
+ <link title="Recording with microphone">https://docs.godotengine.org/en/latest/tutorials/audio/recording_with_microphone.html</link>
</tutorials>
<methods>
<method name="get_recording" qualifiers="const">
diff --git a/doc/classes/AudioServer.xml b/doc/classes/AudioServer.xml
index 49c6f5bb34..d5fd5d8f00 100644
--- a/doc/classes/AudioServer.xml
+++ b/doc/classes/AudioServer.xml
@@ -7,7 +7,7 @@
[AudioServer] is a low-level server interface for audio access. It is in charge of creating sample data (playable audio) as well as its playback via a voice interface.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/audio/audio_buses.html</link>
+ <link title="Audio buses">https://docs.godotengine.org/en/latest/tutorials/audio/audio_buses.html</link>
</tutorials>
<methods>
<method name="add_bus">
diff --git a/doc/classes/AudioStream.xml b/doc/classes/AudioStream.xml
index d5c8e42515..58768dc008 100644
--- a/doc/classes/AudioStream.xml
+++ b/doc/classes/AudioStream.xml
@@ -7,7 +7,7 @@
Base class for audio streams. Audio streams are used for sound effects and music playback, and support WAV (via [AudioStreamSample]) and OGG (via [AudioStreamOGGVorbis]) file formats.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html</link>
+ <link title="Audio streams">https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html</link>
</tutorials>
<methods>
<method name="get_length" qualifiers="const">
diff --git a/doc/classes/AudioStreamGenerator.xml b/doc/classes/AudioStreamGenerator.xml
index e93da411cd..51254f9305 100644
--- a/doc/classes/AudioStreamGenerator.xml
+++ b/doc/classes/AudioStreamGenerator.xml
@@ -5,7 +5,7 @@
<description>
</description>
<tutorials>
- <link>https://github.com/godotengine/godot-demo-projects/tree/master/audio/generator</link>
+ <link title="Audio generator demo project">https://github.com/godotengine/godot-demo-projects/tree/master/audio/generator</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/AudioStreamGeneratorPlayback.xml b/doc/classes/AudioStreamGeneratorPlayback.xml
index e3e17b8a93..cd8e8735b6 100644
--- a/doc/classes/AudioStreamGeneratorPlayback.xml
+++ b/doc/classes/AudioStreamGeneratorPlayback.xml
@@ -5,7 +5,7 @@
<description>
</description>
<tutorials>
- <link>https://github.com/godotengine/godot-demo-projects/tree/master/audio/generator</link>
+ <link title="Audio generator demo project">https://github.com/godotengine/godot-demo-projects/tree/master/audio/generator</link>
</tutorials>
<methods>
<method name="can_push_buffer" qualifiers="const">
diff --git a/doc/classes/AudioStreamPlayer.xml b/doc/classes/AudioStreamPlayer.xml
index dbc3d3e21b..86048ca8c1 100644
--- a/doc/classes/AudioStreamPlayer.xml
+++ b/doc/classes/AudioStreamPlayer.xml
@@ -7,7 +7,7 @@
Plays an audio stream non-positionally.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html</link>
+ <link title="Audio streams">https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html</link>
</tutorials>
<methods>
<method name="get_playback_position">
diff --git a/doc/classes/AudioStreamPlayer2D.xml b/doc/classes/AudioStreamPlayer2D.xml
index 844e2316ba..d8b9385736 100644
--- a/doc/classes/AudioStreamPlayer2D.xml
+++ b/doc/classes/AudioStreamPlayer2D.xml
@@ -7,7 +7,7 @@
Plays audio that dampens with distance from screen center.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html</link>
+ <link title="Audio streams">https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html</link>
</tutorials>
<methods>
<method name="get_playback_position">
diff --git a/doc/classes/AudioStreamPlayer3D.xml b/doc/classes/AudioStreamPlayer3D.xml
index bd90e3bd1a..aadbc865bb 100644
--- a/doc/classes/AudioStreamPlayer3D.xml
+++ b/doc/classes/AudioStreamPlayer3D.xml
@@ -5,9 +5,10 @@
</brief_description>
<description>
Plays a sound effect with directed sound effects, dampens with distance if needed, generates effect of hearable position in space.
+ By default, audio is heard from the camera position. This can be changed by adding a [Listener3D] node to the scene and enabling it by calling [method Listener3D.make_current] on it.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html</link>
+ <link title="Audio streams">https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html</link>
</tutorials>
<methods>
<method name="get_playback_position">
diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml
index 1da4e23437..0cb0b7e57e 100644
--- a/doc/classes/BaseMaterial3D.xml
+++ b/doc/classes/BaseMaterial3D.xml
@@ -7,7 +7,7 @@
This provides a default material with a wide variety of rendering features and properties without the need to write shader code. See the tutorial below for details.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/spatial_material.html</link>
+ <link title="Spatial material">https://docs.godotengine.org/en/latest/tutorials/3d/spatial_material.html</link>
</tutorials>
<methods>
<method name="get_feature" qualifiers="const">
diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml
index 47433d7adc..c614a281ae 100644
--- a/doc/classes/Basis.xml
+++ b/doc/classes/Basis.xml
@@ -10,8 +10,8 @@
For more information, read the "Matrices and transforms" documentation article.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/math/matrices_and_transforms.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html</link>
+ <link title="Matrices and transforms">https://docs.godotengine.org/en/latest/tutorials/math/matrices_and_transforms.html</link>
+ <link title="Using 3D transforms">https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html</link>
</tutorials>
<methods>
<method name="Basis">
diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml
index df3ef71a2a..7244da56ca 100644
--- a/doc/classes/CPUParticles2D.xml
+++ b/doc/classes/CPUParticles2D.xml
@@ -8,7 +8,7 @@
See also [GPUParticles2D], which provides the same functionality with hardware acceleration, but may not run on older devices.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/2d/particle_systems_2d.html</link>
+ <link title="Particle systems (2D)">https://docs.godotengine.org/en/latest/tutorials/2d/particle_systems_2d.html</link>
</tutorials>
<methods>
<method name="convert_from_particles">
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index 899988022f..0eecada4fe 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -12,8 +12,8 @@
[b]Note:[/b] Unless otherwise specified, all methods that have angle parameters must have angles specified as [i]radians[/i]. To convert degrees to radians, use [method @GDScript.deg2rad].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/2d/2d_transforms.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/2d/custom_drawing_in_2d.html</link>
+ <link title="Viewport and canvas transforms">https://docs.godotengine.org/en/latest/tutorials/2d/2d_transforms.html</link>
+ <link title="Custom drawing in 2D">https://docs.godotengine.org/en/latest/tutorials/2d/custom_drawing_in_2d.html</link>
</tutorials>
<methods>
<method name="_draw" qualifiers="virtual">
diff --git a/doc/classes/CanvasLayer.xml b/doc/classes/CanvasLayer.xml
index 8202a29d44..89cd28b617 100644
--- a/doc/classes/CanvasLayer.xml
+++ b/doc/classes/CanvasLayer.xml
@@ -7,8 +7,8 @@
Canvas drawing layer. [CanvasItem] nodes that are direct or indirect children of a [CanvasLayer] will be drawn in that layer. The layer is a numeric index that defines the draw order. The default 2D scene renders with index 0, so a [CanvasLayer] with index -1 will be drawn below, and one with index 1 will be drawn above. This is very useful for HUDs (in layer 1+ or above), or backgrounds (in layer -1 or below).
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/2d/2d_transforms.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/2d/canvas_layers.html</link>
+ <link title="Viewport and canvas transforms">https://docs.godotengine.org/en/latest/tutorials/2d/2d_transforms.html</link>
+ <link title="Canvas layers">https://docs.godotengine.org/en/latest/tutorials/2d/canvas_layers.html</link>
</tutorials>
<methods>
<method name="get_canvas" qualifiers="const">
diff --git a/doc/classes/CharFXTransform.xml b/doc/classes/CharFXTransform.xml
index c16e448498..a988035c36 100644
--- a/doc/classes/CharFXTransform.xml
+++ b/doc/classes/CharFXTransform.xml
@@ -7,8 +7,8 @@
By setting various properties on this object, you can control how individual characters will be displayed in a [RichTextEffect].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/gui/bbcode_in_richtextlabel.html</link>
- <link>https://github.com/Eoin-ONeill-Yokai/Godot-Rich-Text-Effect-Test-Project</link>
+ <link title="BBCode in RichTextLabel">https://docs.godotengine.org/en/latest/tutorials/gui/bbcode_in_richtextlabel.html</link>
+ <link title="RichTextEffect test project (third-party)">https://github.com/Eoin-ONeill-Yokai/Godot-Rich-Text-Effect-Test-Project</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/ClippedCamera3D.xml b/doc/classes/ClippedCamera3D.xml
index 58ecec828d..de90247536 100644
--- a/doc/classes/ClippedCamera3D.xml
+++ b/doc/classes/ClippedCamera3D.xml
@@ -90,7 +90,7 @@
If [code]true[/code], the camera stops on contact with [PhysicsBody3D]s.
</member>
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The camera's collision mask. Only objects in at least one collision layer matching the mask will be detected.
+ The camera's collision mask. Only objects in at least one collision layer matching the mask will be detected. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0">
The camera's collision margin. The camera can't get closer than this distance to a colliding object.
diff --git a/doc/classes/CollisionShape2D.xml b/doc/classes/CollisionShape2D.xml
index d2676e55d0..b4fcf9cd88 100644
--- a/doc/classes/CollisionShape2D.xml
+++ b/doc/classes/CollisionShape2D.xml
@@ -7,7 +7,7 @@
Editor facility for creating and editing collision shapes in 2D space. You can use this node to represent all sorts of collision shapes, for example, add this to an [Area2D] to give it a detection shape, or add it to a [PhysicsBody2D] to create a solid object. [b]IMPORTANT[/b]: this is an Editor-only helper to create shapes, use [method CollisionObject2D.shape_owner_get_shape] to get the actual shape.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
+ <link title="Physics introduction">https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/CollisionShape3D.xml b/doc/classes/CollisionShape3D.xml
index 76515a65a7..177900dd4f 100644
--- a/doc/classes/CollisionShape3D.xml
+++ b/doc/classes/CollisionShape3D.xml
@@ -7,10 +7,10 @@
Editor facility for creating and editing collision shapes in 3D space. You can use this node to represent all sorts of collision shapes, for example, add this to an [Area3D] to give it a detection shape, or add it to a [PhysicsBody3D] to create a solid object. [b]IMPORTANT[/b]: this is an Editor-only helper to create shapes, use [method CollisionObject3D.shape_owner_get_shape] to get the actual shape.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
+ <link title="Physics introduction">https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
</tutorials>
<methods>
- <method name="make_convex_from_brothers">
+ <method name="make_convex_from_siblings">
<return type="void">
</return>
<description>
diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml
index 240e70db9f..fcaba99eb7 100644
--- a/doc/classes/Color.xml
+++ b/doc/classes/Color.xml
@@ -18,13 +18,21 @@
<argument index="0" name="from" type="String">
</argument>
<description>
- Constructs a color from an HTML hexadecimal color string in ARGB or RGB format. See also [method @GDScript.ColorN].
+ Constructs a color from an HTML hexadecimal color string in RGB or RGBA format. See also [method @GDScript.ColorN].
[codeblock]
# Each of the following creates the same color RGBA(178, 217, 10, 255).
- var c1 = Color("#ffb2d90a") # ARGB format with "#".
- var c2 = Color("ffb2d90a") # ARGB format.
var c3 = Color("#b2d90a") # RGB format with "#".
var c4 = Color("b2d90a") # RGB format.
+ var c1 = Color("#b2d90aff") # RGBA format with "#".
+ var c2 = Color("b2d90aff") # RGBA format.
+ [/codeblock]
+ You can also use the "web color" short-hand form by only using 3 or 4 digits.
+ [codeblock]
+ # Each of the following creates the same color RGBA(17, 34, 51, 255).
+ var c3 = Color("#123") # RGB format with "#".
+ var c4 = Color("123") # RGB format.
+ var c1 = Color("#123f") # RGBA format with "#".
+ var c2 = Color("123f") # RGBA format.
[/codeblock]
</description>
</method>
@@ -243,11 +251,11 @@
<argument index="0" name="with_alpha" type="bool" default="true">
</argument>
<description>
- Returns the color's HTML hexadecimal color string in ARGB format (ex: [code]ff34f822[/code]).
- Setting [code]with_alpha[/code] to [code]false[/code] excludes alpha from the hexadecimal string.
+ Returns the color's HTML hexadecimal color string in RGBA format (ex: [code]ff34f822[/code]).
+ Setting [code]with_alpha[/code] to [code]false[/code] excludes alpha from the hexadecimal string (and uses RGB instead of RGBA format).
[codeblock]
var c = Color(1, 1, 1, 0.5)
- var s1 = c.to_html() # Returns "7fffffff"
+ var s1 = c.to_html() # Returns "ffffff7f"
var s2 = c.to_html(false) # Returns "ffffff"
[/codeblock]
</description>
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index 1f495bf91a..c8e37d7d7b 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -13,10 +13,11 @@
Only one [Control] node can be in keyboard focus. Only the node in focus will receive keyboard 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.
+ [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>
- <link>https://docs.godotengine.org/en/latest/tutorials/gui/index.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/2d/custom_drawing_in_2d.html</link>
+ <link title="GUI tutorial index">https://docs.godotengine.org/en/latest/tutorials/gui/index.html</link>
+ <link title="Custom drawing in 2D">https://docs.godotengine.org/en/latest/tutorials/2d/custom_drawing_in_2d.html</link>
</tutorials>
<methods>
<method name="_clips_input" qualifiers="virtual">
@@ -97,7 +98,17 @@
<argument index="1" name="color" type="Color">
</argument>
<description>
- Overrides the [Color] with given [code]name[/code] in the [member theme] resource the control uses. If the [code]color[/code] is empty or invalid, the override is cleared and the color from assigned [Theme] is used.
+ Overrides the [Color] with given [code]name[/code] in the [member theme] resource the control uses.
+ [b]Note:[/b] Unlike other theme overrides, there is no way to undo a color override without manually assigning the previous color.
+ [b]Example of overriding a label's color and resetting it later:[/b]
+ [codeblock]
+ # Override the child node "MyLabel"'s font color to orange.
+ $MyLabel.add_theme_color_override("font_color", Color(1, 0.5, 0))
+
+ # Reset the color by creating a new node to get the default value:
+ var default_label_color = Label.new().get_theme_color("font_color")
+ $MyLabel.add_theme_color_override("font_color", default_label_color)
+ [/codeblock]
</description>
</method>
<method name="add_theme_constant_override">
@@ -108,7 +119,7 @@
<argument index="1" name="constant" type="int">
</argument>
<description>
- Overrides an integer constant with given [code]name[/code] in the [member theme] resource the control uses. If the [code]constant[/code] is empty or invalid, the override is cleared and the constant from assigned [Theme] is used.
+ Overrides an integer constant with given [code]name[/code] in the [member theme] resource the control uses. If the [code]constant[/code] is [code]0[/code], the override is cleared and the constant from assigned [Theme] is used.
</description>
</method>
<method name="add_theme_font_override">
@@ -119,7 +130,7 @@
<argument index="1" name="font" type="Font">
</argument>
<description>
- Overrides the font with given [code]name[/code] in the [member theme] resource the control uses. If [code]font[/code] is empty or invalid, the override is cleared and the font from assigned [Theme] is used.
+ Overrides the font with given [code]name[/code] in the [member theme] resource the control uses. If [code]font[/code] is [code]null[/code] or invalid, the override is cleared and the font from assigned [Theme] is used.
</description>
</method>
<method name="add_theme_icon_override">
@@ -130,7 +141,7 @@
<argument index="1" name="texture" type="Texture2D">
</argument>
<description>
- Overrides the icon with given [code]name[/code] in the [member theme] resource the control uses. If [code]icon[/code] is empty or invalid, the override is cleared and the icon from assigned [Theme] is used.
+ Overrides the icon with given [code]name[/code] in the [member theme] resource the control uses. If [code]icon[/code] is [code]null[/code] or invalid, the override is cleared and the icon from assigned [Theme] is used.
</description>
</method>
<method name="add_theme_shader_override">
@@ -141,7 +152,7 @@
<argument index="1" name="shader" type="Shader">
</argument>
<description>
- Overrides the [Shader] with given [code]name[/code] in the [member theme] resource the control uses. If [code]shader[/code] is empty or invalid, the override is cleared and the shader from assigned [Theme] is used.
+ Overrides the [Shader] with given [code]name[/code] in the [member theme] resource the control uses. If [code]shader[/code] is [code]null[/code] or invalid, the override is cleared and the shader from assigned [Theme] is used.
</description>
</method>
<method name="add_theme_stylebox_override">
@@ -153,6 +164,19 @@
</argument>
<description>
Overrides the [StyleBox] with given [code]name[/code] in the [member theme] resource the control uses. If [code]stylebox[/code] is empty or invalid, the override is cleared and the [StyleBox] from assigned [Theme] is used.
+ [b]Example of modifying a property in a StyleBox by duplicating it:[/b]
+ [codeblock]
+ # 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()
+ new_stylebox_normal.border_width_top = 3
+ new_stylebox_normal.border_color = Color(0, 1, 0.5)
+ $MyButton.add_theme_stylebox_override("normal", new_stylebox_normal)
+
+ # Remove the stylebox override:
+ $MyButton.add_theme_stylebox_override("normal", null)
+ [/codeblock]
</description>
</method>
<method name="can_drop_data" qualifiers="virtual">
diff --git a/doc/classes/Dictionary.xml b/doc/classes/Dictionary.xml
index 5413fa33c6..7123deb206 100644
--- a/doc/classes/Dictionary.xml
+++ b/doc/classes/Dictionary.xml
@@ -73,7 +73,7 @@
[/codeblock]
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/gdscript_basics.html#dictionary</link>
+ <link title="GDScript basics: Dictionary">https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/gdscript_basics.html#dictionary</link>
</tutorials>
<methods>
<method name="clear">
diff --git a/doc/classes/DirectionalLight3D.xml b/doc/classes/DirectionalLight3D.xml
index fc7ce94a2b..afd85a9cb7 100644
--- a/doc/classes/DirectionalLight3D.xml
+++ b/doc/classes/DirectionalLight3D.xml
@@ -7,7 +7,7 @@
A directional light is a type of [Light3D] node that models an infinite number of parallel rays covering the entire scene. It is used for lights with strong intensity that are located far away from the scene to model sunlight or moonlight. The worldspace location of the DirectionalLight3D transform (origin) is ignored. Only the basis is used to determine light direction.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
+ <link title="Lights and shadows">https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/Directory.xml b/doc/classes/Directory.xml
index a86dbfedde..bcdadcd970 100644
--- a/doc/classes/Directory.xml
+++ b/doc/classes/Directory.xml
@@ -24,7 +24,7 @@
[/codeblock]
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/getting_started/step_by_step/filesystem.html</link>
+ <link title="File system">https://docs.godotengine.org/en/latest/getting_started/step_by_step/filesystem.html</link>
</tutorials>
<methods>
<method name="change_dir">
diff --git a/doc/classes/DynamicFont.xml b/doc/classes/DynamicFont.xml
index 5d8ae29175..b0635892be 100644
--- a/doc/classes/DynamicFont.xml
+++ b/doc/classes/DynamicFont.xml
@@ -4,7 +4,7 @@
DynamicFont renders vector font files at runtime.
</brief_description>
<description>
- DynamicFont renders vector font files (such as TTF or OTF) dynamically at runtime instead of using a prerendered texture atlas like [BitmapFont]. This trades the faster loading time of [BitmapFont]s for the ability to change font parameters like size and spacing during runtime. [DynamicFontData] is used for referencing the font file paths. DynamicFont also supports defining one or more fallbacks fonts, which will be used when displaying a character not supported by the main font.
+ DynamicFont renders vector font files (such as TTF or OTF) dynamically at runtime instead of using a prerendered texture atlas like [BitmapFont]. This trades the faster loading time of [BitmapFont]s for the ability to change font parameters like size and spacing during runtime. [DynamicFontData] is used for referencing the font file paths. DynamicFont also supports defining one or more fallback fonts, which will be used when displaying a character not supported by the main font.
DynamicFont uses the [url=https://www.freetype.org/]FreeType[/url] library for rasterization.
[codeblock]
var dynamic_font = DynamicFont.new()
diff --git a/doc/classes/EditorDebuggerPlugin.xml b/doc/classes/EditorDebuggerPlugin.xml
new file mode 100644
index 0000000000..b97933e582
--- /dev/null
+++ b/doc/classes/EditorDebuggerPlugin.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="EditorDebuggerPlugin" inherits="Control" version="4.0">
+ <brief_description>
+ A base class to implement debugger plugins.
+ </brief_description>
+ <description>
+ All debugger plugin scripts must extend [EditorDebuggerPlugin]. It provides functions related to editor side of debugger.
+ You don't need to instantiate this class. That is handled by the debugger itself. [Control] nodes can be added as child nodes to provide a GUI front-end for the plugin.
+ Do not queue_free/reparent it's instance otherwise the instance becomes unusable.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="has_capture">
+ <return type="bool">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ Returns [code]true[/code] if a message capture with given name is present otherwise [code]false[/code].
+ </description>
+ </method>
+ <method name="is_breaked">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if the game is in break state otherwise [code]false[/code].
+ </description>
+ </method>
+ <method name="is_debuggable">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if the game can be debugged otherwise [code]false[/code].
+ </description>
+ </method>
+ <method name="is_session_active">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if there is an instance of the game running with the attached debugger otherwise [code]false[/code].
+ </description>
+ </method>
+ <method name="register_message_capture">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="callable" type="Callable">
+ </argument>
+ <description>
+ Registers a message capture with given [code]name[/code]. If [code]name[/code] is "my_message" then messages starting with "my_message:" will be called with the given callable.
+ Callable must accept a message string and a data array as argument. If the message and data are valid then callable must return [code]true[/code] otherwise [code]false[/code].
+ </description>
+ </method>
+ <method name="send_message">
+ <return type="void">
+ </return>
+ <argument index="0" name="message" type="String">
+ </argument>
+ <argument index="1" name="data" type="Array">
+ </argument>
+ <description>
+ Sends a message with given [code]message[/code] and [code]data[/code] array.
+ </description>
+ </method>
+ <method name="unregister_message_capture">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ Unregisters the message capture with given name.
+ </description>
+ </method>
+ </methods>
+ <signals>
+ <signal name="breaked">
+ <argument index="0" name="can_debug" type="bool">
+ </argument>
+ <description>
+ Emitted when the game enters a break state.
+ </description>
+ </signal>
+ <signal name="continued">
+ <description>
+ Emitted when the game exists a break state.
+ </description>
+ </signal>
+ <signal name="started">
+ <description>
+ Emitted when the debugging starts.
+ </description>
+ </signal>
+ <signal name="stopped">
+ <description>
+ Emitted when the debugging stops.
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/EditorExportPlugin.xml b/doc/classes/EditorExportPlugin.xml
index 6bcaabc39e..9ef2bd21cc 100644
--- a/doc/classes/EditorExportPlugin.xml
+++ b/doc/classes/EditorExportPlugin.xml
@@ -70,24 +70,24 @@
<description>
</description>
</method>
- <method name="add_ios_framework">
+ <method name="add_ios_embedded_framework">
<return type="void">
</return>
<argument index="0" name="path" type="String">
</argument>
<description>
- Adds a static library (*.a) or dynamic library (*.dylib, *.framework) to Linking Phase in iOS's Xcode project.
+ Adds a dynamic library (*.dylib, *.framework) to Linking Phase in iOS's Xcode project and embeds it into resulting binary.
+ [b]Note:[/b] For static libraries (*.a) works in same way as [code]add_ios_framework[/code].
+ This method should not be used for System libraries as they are already present on the device.
</description>
</method>
- <method name="add_ios_embedded_framework">
+ <method name="add_ios_framework">
<return type="void">
</return>
<argument index="0" name="path" type="String">
</argument>
<description>
- Adds a dynamic library (*.dylib, *.framework) to Linking Phase in iOS's Xcode project and embeds it into resulting binary.
- [b]Note:[/b] For static libraries (*.a) works in same way as [code]add_ios_framework[/code].
- This method should not be used for System libraries as they are already present on the device.
+ Adds a static library (*.a) or dynamic library (*.dylib, *.framework) to Linking Phase in iOS's Xcode project.
</description>
</method>
<method name="add_ios_linker_flags">
diff --git a/doc/classes/EditorFeatureProfile.xml b/doc/classes/EditorFeatureProfile.xml
index eb03d3010f..e05a685dd7 100644
--- a/doc/classes/EditorFeatureProfile.xml
+++ b/doc/classes/EditorFeatureProfile.xml
@@ -135,15 +135,15 @@
<constant name="FEATURE_SCENE_TREE" value="3" enum="Feature">
Scene tree editing. If this feature is disabled, the Scene tree dock will still be visible but will be read-only.
</constant>
- <constant name="FEATURE_IMPORT_DOCK" value="4" enum="Feature">
- The Import dock. If this feature is disabled, the Import dock won't be visible.
- </constant>
- <constant name="FEATURE_NODE_DOCK" value="5" enum="Feature">
+ <constant name="FEATURE_NODE_DOCK" value="4" enum="Feature">
The Node dock. If this feature is disabled, signals and groups won't be visible and modifiable from the editor.
</constant>
- <constant name="FEATURE_FILESYSTEM_DOCK" value="6" enum="Feature">
+ <constant name="FEATURE_FILESYSTEM_DOCK" value="5" enum="Feature">
The FileSystem dock. If this feature is disabled, the FileSystem dock won't be visible.
</constant>
+ <constant name="FEATURE_IMPORT_DOCK" value="6" enum="Feature">
+ The Import dock. If this feature is disabled, the Import dock won't be visible.
+ </constant>
<constant name="FEATURE_MAX" value="7" enum="Feature">
Represents the size of the [enum Feature] enum.
</constant>
diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml
index ea2dfae9a5..b290557336 100644
--- a/doc/classes/EditorImportPlugin.xml
+++ b/doc/classes/EditorImportPlugin.xml
@@ -49,7 +49,7 @@
[/codeblock]
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/plugins/editor/import_plugins.html</link>
+ <link title="Import plugins">https://docs.godotengine.org/en/latest/tutorials/plugins/editor/import_plugins.html</link>
</tutorials>
<methods>
<method name="get_import_options" qualifiers="virtual">
diff --git a/doc/classes/EditorNode3DGizmoPlugin.xml b/doc/classes/EditorNode3DGizmoPlugin.xml
index b81281b5b6..8865939eb1 100644
--- a/doc/classes/EditorNode3DGizmoPlugin.xml
+++ b/doc/classes/EditorNode3DGizmoPlugin.xml
@@ -7,7 +7,7 @@
EditorNode3DGizmoPlugin allows you to define a new type of Gizmo. There are two main ways to do so: extending [EditorNode3DGizmoPlugin] for the simpler gizmos, or creating a new [EditorNode3DGizmo] type. See the tutorial in the documentation for more info.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/plugins/editor/spatial_gizmos.html</link>
+ <link title="Spatial gizmo plugins">https://docs.godotengine.org/en/latest/tutorials/plugins/editor/spatial_gizmos.html</link>
</tutorials>
<methods>
<method name="add_material">
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index 99fe9b4bb5..6a64a7aa55 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -7,7 +7,7 @@
Plugins are used by the editor to extend functionality. The most common types of plugins are those which edit a given node or resource type, import plugins and export plugins. See also [EditorScript] to add functions to the editor.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/plugins/editor/index.html</link>
+ <link title="Editor plugins tutorial index">https://docs.godotengine.org/en/latest/tutorials/plugins/editor/index.html</link>
</tutorials>
<methods>
<method name="add_autoload_singleton">
@@ -76,6 +76,15 @@
During run-time, this will be a simple object with a script so this function does not need to be called then.
</description>
</method>
+ <method name="add_debugger_plugin">
+ <return type="void">
+ </return>
+ <argument index="0" name="script" type="Script">
+ </argument>
+ <description>
+ Adds a [Script] as debugger plugin to the Debugger. The script must extend [EditorDebuggerPlugin].
+ </description>
+ </method>
<method name="add_export_plugin">
<return type="void">
</return>
@@ -424,6 +433,15 @@
Removes a custom type added by [method add_custom_type].
</description>
</method>
+ <method name="remove_debugger_plugin">
+ <return type="void">
+ </return>
+ <argument index="0" name="script" type="Script">
+ </argument>
+ <description>
+ Removes the debugger plugin with given script fromm the Debugger.
+ </description>
+ </method>
<method name="remove_export_plugin">
<return type="void">
</return>
diff --git a/doc/classes/EditorScenePostImport.xml b/doc/classes/EditorScenePostImport.xml
index 56fc0e3d1a..cb1f5d2e77 100644
--- a/doc/classes/EditorScenePostImport.xml
+++ b/doc/classes/EditorScenePostImport.xml
@@ -26,7 +26,7 @@
[/codeblock]
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/getting_started/workflow/assets/importing_scenes.html#custom-script</link>
+ <link title="Importing 3D scenes: Custom script">https://docs.godotengine.org/en/latest/getting_started/workflow/assets/importing_scenes.html#custom-script</link>
</tutorials>
<methods>
<method name="get_source_file" qualifiers="const">
diff --git a/doc/classes/EngineDebugger.xml b/doc/classes/EngineDebugger.xml
new file mode 100644
index 0000000000..7db36b89d0
--- /dev/null
+++ b/doc/classes/EngineDebugger.xml
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="EngineDebugger" inherits="Object" version="4.0">
+ <brief_description>
+ Exposes the internal debugger.
+ </brief_description>
+ <description>
+ [EngineDebugger] handles the communication between the editor and the running game. It is active in the running game. Messages can be sent/received through it. It also manages the profilers.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="has_capture">
+ <return type="bool">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ Returns [code]true[/code] if a capture with the given name is present otherwise [code]false[/code].
+ </description>
+ </method>
+ <method name="has_profiler">
+ <return type="bool">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ Returns [code]true[/code] if a profiler with the given name is present otherwise [code]false[/code].
+ </description>
+ </method>
+ <method name="is_active">
+ <return type="bool">
+ </return>
+ <description>
+ Returns [code]true[/code] if the debugger is active otherwise [code]false[/code].
+ </description>
+ </method>
+ <method name="is_profiling">
+ <return type="bool">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ Returns [code]true[/code] if a profiler with the given name is present and active otherwise [code]false[/code].
+ </description>
+ </method>
+ <method name="profiler_add_frame_data">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="data" type="Array">
+ </argument>
+ <description>
+ Calls the [code]add[/code] callable of the profiler with given [code]name[/code] and [code]data[/code].
+ </description>
+ </method>
+ <method name="profiler_enable">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="enable" type="bool">
+ </argument>
+ <argument index="2" name="arguments" type="Array" default="[ ]">
+ </argument>
+ <description>
+ Calls the [code]toggle[/code] callable of the profiler with given [code]name[/code] and [code]arguments[/code]. Enables/Disables the same profiler depending on [code]enable[/code] argument.
+ </description>
+ </method>
+ <method name="register_message_capture">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="callable" type="Callable">
+ </argument>
+ <description>
+ Registers a message capture with given [code]name[/code]. If [code]name[/code] is "my_message" then messages starting with "my_message:" will be called with the given callable.
+ Callable must accept a message string and a data array as argument. If the message and data are valid then callable must return [code]true[/code] otherwise [code]false[/code].
+ </description>
+ </method>
+ <method name="register_profiler">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <argument index="1" name="toggle" type="Callable">
+ </argument>
+ <argument index="2" name="add" type="Callable">
+ </argument>
+ <argument index="3" name="tick" type="Callable">
+ </argument>
+ <description>
+ Registers a profiler with the given [code]name[/code].
+ [code]toggle[/code] callable is called when the profiler is enabled/disabled. It must take an argument array as an argument.
+ [code]add[/code] callable is called when data is added to profiler using [method EngineDebugger.profiler_add_frame_data]. It must take a data array as argument.
+ [code]tick[/code] callable is called at every active profiler iteration. It must take frame time, idle time, physics time, and physics idle time as arguments.
+ </description>
+ </method>
+ <method name="send_message">
+ <return type="void">
+ </return>
+ <argument index="0" name="message" type="String">
+ </argument>
+ <argument index="1" name="data" type="Array">
+ </argument>
+ <description>
+ Sends a message with given [code]message[/code] and [code]data[/code] array.
+ </description>
+ </method>
+ <method name="unregister_message_capture">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ Unregisters the message capture with given [code]name[/code].
+ </description>
+ </method>
+ <method name="unregister_profiler">
+ <return type="void">
+ </return>
+ <argument index="0" name="name" type="StringName">
+ </argument>
+ <description>
+ Unregisters a profiler with given [code]name[/code].
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml
index bbab0bf8cf..caee6a0c07 100644
--- a/doc/classes/Environment.xml
+++ b/doc/classes/Environment.xml
@@ -11,8 +11,8 @@
- Adjustments
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/environment_and_post_processing.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/high_dynamic_range.html</link>
+ <link title="Environment and post-processing">https://docs.godotengine.org/en/latest/tutorials/3d/environment_and_post_processing.html</link>
+ <link title="Light transport in game engines">https://docs.godotengine.org/en/latest/tutorials/3d/high_dynamic_range.html</link>
</tutorials>
<methods>
<method name="is_glow_level_enabled" qualifiers="const">
@@ -95,47 +95,20 @@
<member name="background_mode" type="int" setter="set_background" getter="get_background" enum="Environment.BGMode" default="0">
The background mode. See [enum BGMode] for possible values.
</member>
- <member name="fog_color" type="Color" setter="set_fog_color" getter="get_fog_color" default="Color( 0.5, 0.6, 0.7, 1 )">
- The fog's [Color].
- </member>
- <member name="fog_depth_begin" type="float" setter="set_fog_depth_begin" getter="get_fog_depth_begin" default="10.0">
- The fog's depth starting distance from the camera.
- </member>
- <member name="fog_depth_curve" type="float" setter="set_fog_depth_curve" getter="get_fog_depth_curve" default="1.0">
- The fog depth's intensity curve. A number of presets are available in the [b]Inspector[/b] by right-clicking the curve.
- </member>
- <member name="fog_depth_enabled" type="bool" setter="set_fog_depth_enabled" getter="is_fog_depth_enabled" default="true">
- If [code]true[/code], the depth fog effect is enabled. When enabled, fog will appear in the distance (relative to the camera).
- </member>
- <member name="fog_depth_end" type="float" setter="set_fog_depth_end" getter="get_fog_depth_end" default="100.0">
- The fog's depth end distance from the camera. If this value is set to 0, it will be equal to the current camera's [member Camera3D.far] value.
+ <member name="fog_density" type="float" setter="set_fog_density" getter="get_fog_density" default="0.001">
</member>
<member name="fog_enabled" type="bool" setter="set_fog_enabled" getter="is_fog_enabled" default="false">
- If [code]true[/code], fog effects are enabled. [member fog_height_enabled] and/or [member fog_depth_enabled] must be set to [code]true[/code] to actually display fog.
- </member>
- <member name="fog_height_curve" type="float" setter="set_fog_height_curve" getter="get_fog_height_curve" default="1.0">
- The height fog's intensity. A number of presets are available in the [b]Inspector[/b] by right-clicking the curve.
+ If [code]true[/code], fog effects are enabled.
</member>
- <member name="fog_height_enabled" type="bool" setter="set_fog_height_enabled" getter="is_fog_height_enabled" default="false">
- If [code]true[/code], the height fog effect is enabled. When enabled, fog will appear in a defined height range, regardless of the distance from the camera. This can be used to simulate "deep water" effects with a lower performance cost compared to a dedicated shader.
+ <member name="fog_height" type="float" setter="set_fog_height" getter="get_fog_height" default="0.0">
</member>
- <member name="fog_height_max" type="float" setter="set_fog_height_max" getter="get_fog_height_max" default="0.0">
- The Y coordinate where the height fog will be the most intense. If this value is greater than [member fog_height_min], fog will be displayed from bottom to top. Otherwise, it will be displayed from top to bottom.
+ <member name="fog_height_density" type="float" setter="set_fog_height_density" getter="get_fog_height_density" default="0.0">
</member>
- <member name="fog_height_min" type="float" setter="set_fog_height_min" getter="get_fog_height_min" default="10.0">
- The Y coordinate where the height fog will be the least intense. If this value is greater than [member fog_height_max], fog will be displayed from top to bottom. Otherwise, it will be displayed from bottom to top.
+ <member name="fog_light_color" type="Color" setter="set_fog_light_color" getter="get_fog_light_color" default="Color( 0.5, 0.6, 0.7, 1 )">
</member>
- <member name="fog_sun_amount" type="float" setter="set_fog_sun_amount" getter="get_fog_sun_amount" default="0.0">
- The intensity of the depth fog color transition when looking towards the sun. The sun's direction is determined automatically using the DirectionalLight3D node in the scene.
+ <member name="fog_light_energy" type="float" setter="set_fog_light_energy" getter="get_fog_light_energy" default="1.0">
</member>
- <member name="fog_sun_color" type="Color" setter="set_fog_sun_color" getter="get_fog_sun_color" default="Color( 1, 0.9, 0.7, 1 )">
- The depth fog's [Color] when looking towards the sun.
- </member>
- <member name="fog_transmit_curve" type="float" setter="set_fog_transmit_curve" getter="get_fog_transmit_curve" default="1.0">
- The intensity of the fog light transmittance effect. Amount of light that the fog transmits.
- </member>
- <member name="fog_transmit_enabled" type="bool" setter="set_fog_transmit_enabled" getter="is_fog_transmit_enabled" default="false">
- Enables fog's light transmission effect. If [code]true[/code], light will be more visible in the fog to simulate light scattering as in real life.
+ <member name="fog_sun_scatter" type="float" setter="set_fog_sun_scatter" getter="get_fog_sun_scatter" default="0.0">
</member>
<member name="glow_blend_mode" type="int" setter="set_glow_blend_mode" getter="get_glow_blend_mode" enum="Environment.GlowBlendMode" default="2">
The glow blending mode.
@@ -265,6 +238,22 @@
<member name="tonemap_white" type="float" setter="set_tonemap_white" getter="get_tonemap_white" default="1.0">
The white reference value for tonemapping. Only effective if the [member tonemap_mode] isn't set to [constant TONE_MAPPER_LINEAR].
</member>
+ <member name="volumetric_fog_density" type="float" setter="set_volumetric_fog_density" getter="get_volumetric_fog_density" default="0.01">
+ </member>
+ <member name="volumetric_fog_detail_spread" type="float" setter="set_volumetric_fog_detail_spread" getter="get_volumetric_fog_detail_spread" default="2.0">
+ </member>
+ <member name="volumetric_fog_enabled" type="bool" setter="set_volumetric_fog_enabled" getter="is_volumetric_fog_enabled" default="false">
+ </member>
+ <member name="volumetric_fog_gi_inject" type="float" setter="set_volumetric_fog_gi_inject" getter="get_volumetric_fog_gi_inject" default="0.0">
+ </member>
+ <member name="volumetric_fog_length" type="float" setter="set_volumetric_fog_length" getter="get_volumetric_fog_length" default="64.0">
+ </member>
+ <member name="volumetric_fog_light" type="Color" setter="set_volumetric_fog_light" getter="get_volumetric_fog_light" default="Color( 0, 0, 0, 1 )">
+ </member>
+ <member name="volumetric_fog_light_energy" type="float" setter="set_volumetric_fog_light_energy" getter="get_volumetric_fog_light_energy" default="1.0">
+ </member>
+ <member name="volumetric_fog_shadow_filter" type="int" setter="set_volumetric_fog_shadow_filter" getter="get_volumetric_fog_shadow_filter" enum="Environment.VolumetricFogShadowFilter" default="1">
+ </member>
</members>
<constants>
<constant name="BG_CLEAR_COLOR" value="0" enum="BGMode">
@@ -360,5 +349,13 @@
</constant>
<constant name="SDFGI_Y_SCALE_50_PERCENT" value="2" enum="SDFGIYScale">
</constant>
+ <constant name="VOLUMETRIC_FOG_SHADOW_FILTER_DISABLED" value="0" enum="VolumetricFogShadowFilter">
+ </constant>
+ <constant name="VOLUMETRIC_FOG_SHADOW_FILTER_LOW" value="1" enum="VolumetricFogShadowFilter">
+ </constant>
+ <constant name="VOLUMETRIC_FOG_SHADOW_FILTER_MEDIUM" value="2" enum="VolumetricFogShadowFilter">
+ </constant>
+ <constant name="VOLUMETRIC_FOG_SHADOW_FILTER_HIGH" value="3" enum="VolumetricFogShadowFilter">
+ </constant>
</constants>
</class>
diff --git a/doc/classes/Expression.xml b/doc/classes/Expression.xml
index fcd1aa43c0..f2611dc850 100644
--- a/doc/classes/Expression.xml
+++ b/doc/classes/Expression.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
An expression can be made of any arithmetic operation, built-in math function call, method call of a passed instance, or built-in type construction call.
- An example expression text using the built-in math functions could be [code]sqrt(pow(3,2) + pow(4,2))[/code].
+ An example expression text using the built-in math functions could be [code]sqrt(pow(3, 2) + pow(4, 2))[/code].
In the following example we use a [LineEdit] node to write our expression and show the result.
[codeblock]
onready var expression = Expression.new()
diff --git a/doc/classes/File.xml b/doc/classes/File.xml
index d91203d91f..1982406993 100644
--- a/doc/classes/File.xml
+++ b/doc/classes/File.xml
@@ -23,7 +23,7 @@
In the example above, the file will be saved in the user data folder as specified in the [url=https://docs.godotengine.org/en/latest/tutorials/io/data_paths.html]Data paths[/url] documentation.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/getting_started/step_by_step/filesystem.html</link>
+ <link title="File system">https://docs.godotengine.org/en/latest/getting_started/step_by_step/filesystem.html</link>
</tutorials>
<methods>
<method name="close">
@@ -451,16 +451,16 @@
</members>
<constants>
<constant name="READ" value="1" enum="ModeFlags">
- Opens the file for read operations.
+ Opens the file for read operations. The cursor is positioned at the beginning of the file.
</constant>
<constant name="WRITE" value="2" enum="ModeFlags">
- Opens the file for write operations. Create it if the file does not exist and truncate if it exists.
+ Opens the file for write operations. The file is created if it does not exist, and truncated if it does.
</constant>
<constant name="READ_WRITE" value="3" enum="ModeFlags">
- Opens the file for read and write operations. Does not truncate the file.
+ Opens the file for read and write operations. Does not truncate the file. The cursor is positioned at the beginning of the file.
</constant>
<constant name="WRITE_READ" value="7" enum="ModeFlags">
- Opens the file for read and write operations. Create it if the file does not exist and truncate if it exists.
+ Opens the file for read and write operations. The file is created if it does not exist, and truncated if it does. The cursor is positioned at the beginning of the file.
</constant>
<constant name="COMPRESSION_FASTLZ" value="0" enum="CompressionMode">
Uses the [url=http://fastlz.org/]FastLZ[/url] compression method.
diff --git a/doc/classes/FileDialog.xml b/doc/classes/FileDialog.xml
index eaaccbd0dd..b4afee7610 100644
--- a/doc/classes/FileDialog.xml
+++ b/doc/classes/FileDialog.xml
@@ -57,6 +57,7 @@
<members>
<member name="access" type="int" setter="set_access" getter="get_access" enum="FileDialog.Access" default="0">
The file system access scope. See enum [code]Access[/code] constants.
+ [b]Warning:[/b] Currently, in sandboxed environments such as HTML5 builds or sandboxed macOS apps, FileDialog cannot access the host file system. See [url=https://github.com/godotengine/godot-proposals/issues/1123]godot-proposals#1123[/url].
</member>
<member name="current_dir" type="String" setter="set_current_dir" getter="get_current_dir" default="&quot;res://&quot;">
The current working directory of the file dialog.
diff --git a/doc/classes/Font.xml b/doc/classes/Font.xml
index ce6a25e191..f49fbf0d2a 100644
--- a/doc/classes/Font.xml
+++ b/doc/classes/Font.xml
@@ -5,6 +5,8 @@
</brief_description>
<description>
Font contains a Unicode-compatible character set, as well as the ability to draw it with variable width, ascent, descent and kerning. For creating fonts from TTF files (or other font formats), see the editor support for fonts.
+ [b]Note:[/b] If a DynamicFont doesn't contain a character used in a string, the character in question will be replaced with codepoint [code]0xfffd[/code] if it's available in the DynamicFont. If this replacement character isn't available in the DynamicFont, the character will be hidden without displaying any replacement character in the string.
+ [b]Note:[/b] If a BitmapFont doesn't contain a character used in a string, the character in question will be hidden without displaying any replacement character in the string.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/GIProbe.xml b/doc/classes/GIProbe.xml
index 8885f360a3..9199468ab3 100644
--- a/doc/classes/GIProbe.xml
+++ b/doc/classes/GIProbe.xml
@@ -8,7 +8,7 @@
Having [GIProbe]s in a scene can be expensive, the quality of the probe can be turned down in exchange for better performance in the [ProjectSettings] using [member ProjectSettings.rendering/quality/gi_probes/quality].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/gi_probes.html</link>
+ <link title="GI probes">https://docs.godotengine.org/en/latest/tutorials/3d/gi_probes.html</link>
</tutorials>
<methods>
<method name="bake">
diff --git a/doc/classes/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml
index ee67b5052c..244bdcf2f3 100644
--- a/doc/classes/GPUParticles2D.xml
+++ b/doc/classes/GPUParticles2D.xml
@@ -8,7 +8,7 @@
Use the [code]process_material[/code] property to add a [ParticlesMaterial] to configure particle appearance and behavior. Alternatively, you can add a [ShaderMaterial] which will be applied to all particles.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/2d/particle_systems_2d.html</link>
+ <link title="Particle systems (2D)">https://docs.godotengine.org/en/latest/tutorials/2d/particle_systems_2d.html</link>
</tutorials>
<methods>
<method name="capture_rect" qualifiers="const">
@@ -33,7 +33,7 @@
<member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" enum="GPUParticles2D.DrawOrder" default="0">
Particle draw order. Uses [enum DrawOrder] values.
</member>
- <member name="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="false">
+ <member name="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="true">
If [code]true[/code], particles are being emitted.
</member>
<member name="explosiveness" type="float" setter="set_explosiveness_ratio" getter="get_explosiveness_ratio" default="0.0">
diff --git a/doc/classes/GPUParticles3D.xml b/doc/classes/GPUParticles3D.xml
index add8f28bf8..3fc9e73ccf 100644
--- a/doc/classes/GPUParticles3D.xml
+++ b/doc/classes/GPUParticles3D.xml
@@ -8,7 +8,7 @@
Use the [code]process_material[/code] property to add a [ParticlesMaterial] to configure particle appearance and behavior. Alternatively, you can add a [ShaderMaterial] which will be applied to all particles.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/vertex_animation/controlling_thousands_of_fish.html</link>
+ <link title="Controlling thousands of fish with Particles">https://docs.godotengine.org/en/latest/tutorials/3d/vertex_animation/controlling_thousands_of_fish.html</link>
</tutorials>
<methods>
<method name="capture_aabb" qualifiers="const">
@@ -68,7 +68,7 @@
<member name="draw_passes" type="int" setter="set_draw_passes" getter="get_draw_passes" default="1">
The number of draw passes when rendering particles.
</member>
- <member name="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="false">
+ <member name="emitting" type="bool" setter="set_emitting" getter="is_emitting" default="true">
If [code]true[/code], particles are being emitted.
</member>
<member name="explosiveness" type="float" setter="set_explosiveness_ratio" getter="get_explosiveness_ratio" default="0.0">
diff --git a/doc/classes/GridContainer.xml b/doc/classes/GridContainer.xml
index e13dc43104..6ee794c5c4 100644
--- a/doc/classes/GridContainer.xml
+++ b/doc/classes/GridContainer.xml
@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GridContainer" inherits="Container" version="4.0">
<brief_description>
- Grid container used to arrange elements in a grid like layout.
+ Grid container used to arrange Control-derived children in a grid like layout.
</brief_description>
<description>
- Grid container will arrange its children in a grid like structure, the grid columns are specified using the [member columns] property and the number of rows will be equal to the number of children in the container divided by the number of columns. For example, if the container has 5 children, and 2 columns, there will be 3 rows in the container.
+ GridContainer will arrange its Control-derived children in a grid like structure, the grid columns are specified using the [member columns] property and the number of rows will be equal to the number of children in the container divided by the number of columns. For example, if the container has 5 children, and 2 columns, there will be 3 rows in the container.
Notice that grid layout will preserve the columns and rows for every size of the container, and that empty columns will be expanded automatically.
+ [b]Note:[/b] GridContainer only works with child nodes inheriting from Control. It won't rearrange child nodes inheriting from Node2D.
</description>
<tutorials>
</tutorials>
@@ -13,7 +14,7 @@
</methods>
<members>
<member name="columns" type="int" setter="set_columns" getter="get_columns" default="1">
- The number of columns in the [GridContainer]. If modified, [GridContainer] reorders its children to accommodate the new layout.
+ The number of columns in the [GridContainer]. If modified, [GridContainer] reorders its Control-derived children to accommodate the new layout.
</member>
</members>
<constants>
diff --git a/doc/classes/HTTPClient.xml b/doc/classes/HTTPClient.xml
index 7e8f0807ac..9dc38b018a 100644
--- a/doc/classes/HTTPClient.xml
+++ b/doc/classes/HTTPClient.xml
@@ -1,18 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="HTTPClient" inherits="Reference" version="4.0">
<brief_description>
- Hyper-text transfer protocol client.
+ Low-level hyper-text transfer protocol client.
</brief_description>
<description>
- Hyper-text transfer protocol client (sometimes called "User Agent"). Used to make HTTP requests to download web content, upload files and other data or to communicate with various services, among other use cases. See [HTTPRequest] for an higher-level alternative.
+ Hyper-text transfer protocol client (sometimes called "User Agent"). Used to make HTTP requests to download web content, upload files and other data or to communicate with various services, among other use cases. [b]See the [HTTPRequest] node for an higher-level alternative.[/b]
[b]Note:[/b] This client only needs to connect to a host once (see [method connect_to_host]) to send multiple requests. Because of this, methods that take URLs usually take just the part after the host instead of the full URL, as the client is already connected to a host. See [method request] for a full example and to get started.
A [HTTPClient] should be reused between multiple requests or to connect to different hosts instead of creating one client per request. Supports SSL and SSL server certificate verification. HTTP status codes in the 2xx range indicate success, 3xx redirection (i.e. "try again, but over here"), 4xx something was wrong with the request, and 5xx something went wrong on the server's side.
For more information on HTTP, see https://developer.mozilla.org/en-US/docs/Web/HTTP (or read RFC 2616 to get it straight from the source: https://tools.ietf.org/html/rfc2616).
[b]Note:[/b] When performing HTTP requests from a project exported to HTML5, keep in mind the remote server may not allow requests from foreign origins due to [url=https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS]CORS[/url]. If you host the server in question, you should modify its backend to allow requests from foreign origins by adding the [code]Access-Control-Allow-Origin: *[/code] HTTP header.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/networking/http_client_class.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/networking/ssl_certificates.html</link>
+ <link title="HTTP client class">https://docs.godotengine.org/en/latest/tutorials/networking/http_client_class.html</link>
+ <link title="SSL certificates">https://docs.godotengine.org/en/latest/tutorials/networking/ssl_certificates.html</link>
</tutorials>
<methods>
<method name="close">
@@ -152,6 +152,7 @@
var headers = ["Content-Type: application/x-www-form-urlencoded", "Content-Length: " + str(query_string.length())]
var result = http_client.request(http_client.METHOD_POST, "index.php", headers, query_string)
[/codeblock]
+ [b]Note:[/b] The [code]request_data[/code] parameter is ignored if [code]method[/code] is [constant HTTPClient.METHOD_GET]. This is because GET methods can't contain request data. As a workaround, you can pass request data as a query string in the URL. See [method String.http_escape] for an example.
</description>
</method>
<method name="request_raw">
diff --git a/doc/classes/HTTPRequest.xml b/doc/classes/HTTPRequest.xml
index 61e0d2e2b9..4801af07d3 100644
--- a/doc/classes/HTTPRequest.xml
+++ b/doc/classes/HTTPRequest.xml
@@ -67,8 +67,8 @@
[b]Note:[/b] When performing HTTP requests from a project exported to HTML5, keep in mind the remote server may not allow requests from foreign origins due to [url=https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS]CORS[/url]. If you host the server in question, you should modify its backend to allow requests from foreign origins by adding the [code]Access-Control-Allow-Origin: *[/code] HTTP header.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/networking/http_request_class.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/networking/ssl_certificates.html</link>
+ <link title="Making HTTP requests">https://docs.godotengine.org/en/latest/tutorials/networking/http_request_class.html</link>
+ <link title="SSL certificates">https://docs.godotengine.org/en/latest/tutorials/networking/ssl_certificates.html</link>
</tutorials>
<methods>
<method name="cancel_request">
@@ -116,6 +116,7 @@
<description>
Creates request on the underlying [HTTPClient]. If there is no configuration errors, it tries to connect using [method HTTPClient.connect_to_host] and passes parameters onto [method HTTPClient.request].
Returns [constant OK] if request is successfully created. (Does not imply that the server has responded), [constant ERR_UNCONFIGURED] if not in the tree, [constant ERR_BUSY] if still processing previous request, [constant ERR_INVALID_PARAMETER] if given string is not a valid URL format, or [constant ERR_CANT_CONNECT] if not using thread and the [HTTPClient] cannot connect to host.
+ [b]Note:[/b] The [code]request_data[/code] parameter is ignored if [code]method[/code] is [constant HTTPClient.METHOD_GET]. This is because GET methods can't contain request data. As a workaround, you can pass request data as a query string in the URL. See [method String.http_escape] for an example.
</description>
</method>
</methods>
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index fc3c3776ce..b05ab5b4d6 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -7,7 +7,7 @@
A singleton that deals with inputs. This includes key presses, mouse buttons and movement, joypads, and input actions. Actions and their events can be set in the [b]Input Map[/b] tab in the [b]Project &gt; Project Settings[/b], or with the [InputMap] class.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/inputs/index.html</link>
+ <link title="Inputs tutorial index">https://docs.godotengine.org/en/latest/tutorials/inputs/index.html</link>
</tutorials>
<methods>
<method name="action_press">
@@ -47,8 +47,9 @@
<return type="Vector3">
</return>
<description>
- If the device has an accelerometer, this will return the acceleration. Otherwise, it returns an empty [Vector3].
+ Returns the acceleration of the device's accelerometer, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
Note this method returns an empty [Vector3] when running from the editor even when your device has an accelerometer. You must export your project to a supported device to read values from the accelerometer.
+ [b]Note:[/b] This method only works on iOS, Android, and UWP. On other platforms, it always returns [constant Vector3.ZERO].
</description>
</method>
<method name="get_action_strength" qualifiers="const">
@@ -78,14 +79,16 @@
<return type="Vector3">
</return>
<description>
- If the device has an accelerometer, this will return the gravity. Otherwise, it returns an empty [Vector3].
+ Returns the gravity of the device's accelerometer, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
+ [b]Note:[/b] This method only works on Android and iOS. On other platforms, it always returns [constant Vector3.ZERO].
</description>
</method>
<method name="get_gyroscope" qualifiers="const">
<return type="Vector3">
</return>
<description>
- If the device has a gyroscope, this will return the rate of rotation in rad/s around a device's X, Y, and Z axes. Otherwise, it returns an empty [Vector3].
+ Returns the rotation rate in rad/s around a device's X, Y, and Z axes of the gyroscope, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
+ [b]Note:[/b] This method only works on Android. On other platforms, it always returns [constant Vector3.ZERO].
</description>
</method>
<method name="get_joy_axis" qualifiers="const">
@@ -182,7 +185,8 @@
<return type="Vector3">
</return>
<description>
- If the device has a magnetometer, this will return the magnetic field strength in micro-Tesla for all axes.
+ Returns the the magnetic field strength in micro-Tesla for all axes of the device's magnetometer, if the device has one. Otherwise, the method returns [constant Vector3.ZERO].
+ [b]Note:[/b] This method only works on Android and UWP. On other platforms, it always returns [constant Vector3.ZERO].
</description>
</method>
<method name="get_mouse_button_mask" qualifiers="const">
@@ -417,7 +421,8 @@
Makes the mouse cursor hidden if it is visible.
</constant>
<constant name="MOUSE_MODE_CAPTURED" value="2" enum="MouseMode">
- Captures the mouse. The mouse will be hidden and unable to leave the game window, but it will still register movement and mouse button presses. On Windows and Linux, the mouse will use raw input mode, which means the reported movement will be unaffected by the OS' mouse acceleration settings.
+ Captures the mouse. The mouse will be hidden and its position locked at the center of the screen.
+ [b]Note:[/b] If you want to process the mouse's movement in this mode, you need to use [member InputEventMouseMotion.relative].
</constant>
<constant name="MOUSE_MODE_CONFINED" value="3" enum="MouseMode">
Makes the mouse cursor visible but confines it to the game window.
diff --git a/doc/classes/InputEvent.xml b/doc/classes/InputEvent.xml
index 413e217b45..3663ee98cc 100644
--- a/doc/classes/InputEvent.xml
+++ b/doc/classes/InputEvent.xml
@@ -7,8 +7,8 @@
Base class of all sort of input event. See [method Node._input].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/2d/2d_transforms.html</link>
+ <link title="InputEvent">https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
+ <link title="Viewport and canvas transforms">https://docs.godotengine.org/en/latest/tutorials/2d/2d_transforms.html</link>
</tutorials>
<methods>
<method name="accumulate">
diff --git a/doc/classes/InputEventAction.xml b/doc/classes/InputEventAction.xml
index 1c38ff8e8f..e0d3e47219 100644
--- a/doc/classes/InputEventAction.xml
+++ b/doc/classes/InputEventAction.xml
@@ -7,7 +7,7 @@
Contains a generic action which can be targeted from several types of inputs. Actions can be created from the [b]Input Map[/b] tab in the [b]Project &gt; Project Settings[/b] menu. See [method Node._input].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html#actions</link>
+ <link title="InputEvent: Actions">https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html#actions</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/InputEventJoypadButton.xml b/doc/classes/InputEventJoypadButton.xml
index 7876bace75..6ab4942f85 100644
--- a/doc/classes/InputEventJoypadButton.xml
+++ b/doc/classes/InputEventJoypadButton.xml
@@ -7,7 +7,7 @@
Input event type for gamepad buttons. For gamepad analog sticks and joysticks, see [InputEventJoypadMotion].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
+ <link title="InputEvent">https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/InputEventJoypadMotion.xml b/doc/classes/InputEventJoypadMotion.xml
index bfd961ce1f..2d7787b568 100644
--- a/doc/classes/InputEventJoypadMotion.xml
+++ b/doc/classes/InputEventJoypadMotion.xml
@@ -7,7 +7,7 @@
Stores information about joystick motions. One [InputEventJoypadMotion] represents one axis at a time.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
+ <link title="InputEvent">https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/InputEventKey.xml b/doc/classes/InputEventKey.xml
index 767e67c615..fe91b9c13e 100644
--- a/doc/classes/InputEventKey.xml
+++ b/doc/classes/InputEventKey.xml
@@ -7,7 +7,7 @@
Stores key presses on the keyboard. Supports key presses, key releases and [member echo] events.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
+ <link title="InputEvent">https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
</tutorials>
<methods>
<method name="get_keycode_with_modifiers" qualifiers="const">
diff --git a/doc/classes/InputEventMouse.xml b/doc/classes/InputEventMouse.xml
index e3c9d688d2..31e82bbaed 100644
--- a/doc/classes/InputEventMouse.xml
+++ b/doc/classes/InputEventMouse.xml
@@ -7,7 +7,7 @@
Stores general mouse events information.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
+ <link title="InputEvent">https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/InputEventMouseButton.xml b/doc/classes/InputEventMouseButton.xml
index b83588a877..d7b64a9a2d 100644
--- a/doc/classes/InputEventMouseButton.xml
+++ b/doc/classes/InputEventMouseButton.xml
@@ -7,7 +7,7 @@
Contains mouse click information. See [method Node._input].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/inputs/mouse_and_input_coordinates.html</link>
+ <link title="Mouse and input coordinates">https://docs.godotengine.org/en/latest/tutorials/inputs/mouse_and_input_coordinates.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/InputEventMouseMotion.xml b/doc/classes/InputEventMouseMotion.xml
index c36089fe9b..3e64fd63ab 100644
--- a/doc/classes/InputEventMouseMotion.xml
+++ b/doc/classes/InputEventMouseMotion.xml
@@ -8,7 +8,7 @@
[b]Note:[/b] By default, this event is only emitted once per frame rendered at most. If you need more precise input reporting, call [method Input.set_use_accumulated_input] with [code]false[/code] to make events emitted as often as possible. If you use InputEventMouseMotion to draw lines, consider implementing [url=https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm]Bresenham's line algorithm[/url] as well to avoid visible gaps in lines if the user is moving the mouse quickly.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/inputs/mouse_and_input_coordinates.html</link>
+ <link title="Mouse and input coordinates">https://docs.godotengine.org/en/latest/tutorials/inputs/mouse_and_input_coordinates.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/InputEventScreenDrag.xml b/doc/classes/InputEventScreenDrag.xml
index a315e4ddfb..d69f175be8 100644
--- a/doc/classes/InputEventScreenDrag.xml
+++ b/doc/classes/InputEventScreenDrag.xml
@@ -7,7 +7,7 @@
Contains screen drag information. See [method Node._input].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
+ <link title="InputEvent">https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/InputEventScreenTouch.xml b/doc/classes/InputEventScreenTouch.xml
index 16a3cf8353..f497f2fecc 100644
--- a/doc/classes/InputEventScreenTouch.xml
+++ b/doc/classes/InputEventScreenTouch.xml
@@ -8,7 +8,7 @@
Stores multi-touch press/release information. Supports touch press, touch release and [member index] for multi-touch count and order.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
+ <link title="InputEvent">https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/InputEventWithModifiers.xml b/doc/classes/InputEventWithModifiers.xml
index cc7de2ca32..667879a922 100644
--- a/doc/classes/InputEventWithModifiers.xml
+++ b/doc/classes/InputEventWithModifiers.xml
@@ -7,7 +7,7 @@
Contains keys events information with modifiers support like [kbd]Shift[/kbd] or [kbd]Alt[/kbd]. See [method Node._input].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
+ <link title="InputEvent">https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/InputMap.xml b/doc/classes/InputMap.xml
index 03212538c9..062ac3869d 100644
--- a/doc/classes/InputMap.xml
+++ b/doc/classes/InputMap.xml
@@ -7,7 +7,7 @@
Manages all [InputEventAction] which can be created/modified from the project settings menu [b]Project &gt; Project Settings &gt; Input Map[/b] or in code with [method add_action] and [method action_add_event]. See [method Node._input].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html#inputmap</link>
+ <link title="InputEvent: InputMap">https://docs.godotengine.org/en/latest/tutorials/inputs/inputevent.html#inputmap</link>
</tutorials>
<methods>
<method name="action_add_event">
diff --git a/doc/classes/JavaScript.xml b/doc/classes/JavaScript.xml
index 68f6c32a53..d2cb558385 100644
--- a/doc/classes/JavaScript.xml
+++ b/doc/classes/JavaScript.xml
@@ -7,7 +7,7 @@
The JavaScript singleton is implemented only in the HTML5 export. It's used to access the browser's JavaScript context. This allows interaction with embedding pages or calling third-party JavaScript APIs.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/getting_started/workflow/export/exporting_for_web.html#calling-javascript-from-script</link>
+ <link title="Exporting for the Web: Calling JavaScript from script">https://docs.godotengine.org/en/latest/getting_started/workflow/export/exporting_for_web.html#calling-javascript-from-script</link>
</tutorials>
<methods>
<method name="eval">
diff --git a/doc/classes/KinematicBody2D.xml b/doc/classes/KinematicBody2D.xml
index 455fdad771..5a1b4630d0 100644
--- a/doc/classes/KinematicBody2D.xml
+++ b/doc/classes/KinematicBody2D.xml
@@ -10,7 +10,7 @@
</description>
<tutorials>
<link title="Kinematic character (2D)">https://docs.godotengine.org/en/latest/tutorials/physics/kinematic_character_2d.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/using_kinematic_body_2d.html</link>
+ <link title="Using KinematicBody2D">https://docs.godotengine.org/en/latest/tutorials/physics/using_kinematic_body_2d.html</link>
</tutorials>
<methods>
<method name="get_floor_normal" qualifiers="const">
diff --git a/doc/classes/KinematicBody3D.xml b/doc/classes/KinematicBody3D.xml
index 01cce907f9..5d9c7fd896 100644
--- a/doc/classes/KinematicBody3D.xml
+++ b/doc/classes/KinematicBody3D.xml
@@ -9,7 +9,7 @@
[b]Kinematic characters:[/b] KinematicBody3D also has an API for moving objects (the [method move_and_collide] and [method move_and_slide] methods) while performing collision tests. This makes them really useful to implement characters that collide against a world, but that don't require advanced physics.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/kinematic_character_2d.html</link>
+ <link title="Kinematic character (2D)">https://docs.godotengine.org/en/latest/tutorials/physics/kinematic_character_2d.html</link>
</tutorials>
<methods>
<method name="get_axis_lock" qualifiers="const">
diff --git a/doc/classes/Light2D.xml b/doc/classes/Light2D.xml
index 2862190d4d..c5f0c2df8c 100644
--- a/doc/classes/Light2D.xml
+++ b/doc/classes/Light2D.xml
@@ -8,7 +8,7 @@
[b]Note:[/b] Light2D can also be used as a mask.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/2d/2d_lights_and_shadows.html</link>
+ <link title="2D lights and shadows">https://docs.godotengine.org/en/latest/tutorials/2d/2d_lights_and_shadows.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/Light3D.xml b/doc/classes/Light3D.xml
index 6979efa569..c022e56a39 100644
--- a/doc/classes/Light3D.xml
+++ b/doc/classes/Light3D.xml
@@ -7,7 +7,7 @@
Light3D is the [i]abstract[/i] base class for light nodes. As it can't be instanced, it shouldn't be used directly. Other types of light nodes inherit from it. Light3D contains the common variables and parameters used for lighting.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
+ <link title="3D lights and shadows">https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
</tutorials>
<methods>
<method name="get_param" qualifiers="const">
@@ -77,6 +77,8 @@
<member name="shadow_enabled" type="bool" setter="set_shadow" getter="has_shadow" default="false">
If [code]true[/code], the light will cast shadows.
</member>
+ <member name="shadow_fog_fade" type="float" setter="set_param" getter="get_param" default="1.0">
+ </member>
<member name="shadow_normal_bias" type="float" setter="set_param" getter="get_param" default="2.0">
Offsets the lookup into the shadow map by the object's normal. This can be used to reduce self-shadowing artifacts without using [member shadow_bias]. In practice, this value should be tweaked along with [member shadow_bias] to reduce artifacts as much as possible.
</member>
@@ -138,10 +140,12 @@
<constant name="PARAM_SHADOW_BLUR" value="16" enum="Param">
Constant for accessing [member shadow_blur].
</constant>
- <constant name="PARAM_TRANSMITTANCE_BIAS" value="17" enum="Param">
+ <constant name="PARAM_SHADOW_VOLUMETRIC_FOG_FADE" value="17" enum="Param">
+ </constant>
+ <constant name="PARAM_TRANSMITTANCE_BIAS" value="18" enum="Param">
Constant for accessing [member shadow_transmittance_bias].
</constant>
- <constant name="PARAM_MAX" value="18" enum="Param">
+ <constant name="PARAM_MAX" value="19" enum="Param">
Represents the size of the [enum Param] enum.
</constant>
<constant name="BAKE_DISABLED" value="0" enum="BakeMode">
diff --git a/doc/classes/LightOccluder2D.xml b/doc/classes/LightOccluder2D.xml
index a02f7a0f75..9f128e5942 100644
--- a/doc/classes/LightOccluder2D.xml
+++ b/doc/classes/LightOccluder2D.xml
@@ -7,7 +7,7 @@
Occludes light cast by a Light2D, casting shadows. The LightOccluder2D must be provided with an [OccluderPolygon2D] in order for the shadow to be computed.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/2d/2d_lights_and_shadows.html</link>
+ <link title="2D lights and shadows">https://docs.godotengine.org/en/latest/tutorials/2d/2d_lights_and_shadows.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/MeshInstance2D.xml b/doc/classes/MeshInstance2D.xml
index 689f8d83e1..59b312f69a 100644
--- a/doc/classes/MeshInstance2D.xml
+++ b/doc/classes/MeshInstance2D.xml
@@ -7,7 +7,7 @@
Node used for displaying a [Mesh] in 2D. Can be constructed from an existing [Sprite2D] via a tool in the editor toolbar. Select "Sprite2D" then "Convert to Mesh2D", select settings in popup and press "Create Mesh2D".
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/2d/2d_meshes.html</link>
+ <link title="2D meshes">https://docs.godotengine.org/en/latest/tutorials/2d/2d_meshes.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml
index 0f56ab4b95..8a6c560cdd 100644
--- a/doc/classes/MultiMesh.xml
+++ b/doc/classes/MultiMesh.xml
@@ -10,8 +10,8 @@
Since instances may have any behavior, the AABB used for visibility must be provided by the user.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/vertex_animation/animating_thousands_of_fish.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/optimization/using_multimesh.html</link>
+ <link title="Animating thousands of fish with MultiMeshInstance">https://docs.godotengine.org/en/latest/tutorials/3d/vertex_animation/animating_thousands_of_fish.html</link>
+ <link title="Optimization using MultiMeshes">https://docs.godotengine.org/en/latest/tutorials/optimization/using_multimesh.html</link>
</tutorials>
<methods>
<method name="get_aabb" qualifiers="const">
diff --git a/doc/classes/MultiMeshInstance3D.xml b/doc/classes/MultiMeshInstance3D.xml
index cab17c952e..7d8035ba77 100644
--- a/doc/classes/MultiMeshInstance3D.xml
+++ b/doc/classes/MultiMeshInstance3D.xml
@@ -8,9 +8,9 @@
This is useful to optimize the rendering of a high amount of instances of a given mesh (for example trees in a forest or grass strands).
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/vertex_animation/animating_thousands_of_fish.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/using_multi_mesh_instance.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/optimization/using_multimesh.html</link>
+ <link title="Animating thousands of fish with MultiMeshInstance">https://docs.godotengine.org/en/latest/tutorials/3d/vertex_animation/animating_thousands_of_fish.html</link>
+ <link title="Using MultiMeshInstance">https://docs.godotengine.org/en/latest/tutorials/3d/using_multi_mesh_instance.html</link>
+ <link title="Optimization using MultiMeshes">https://docs.godotengine.org/en/latest/tutorials/optimization/using_multimesh.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/Mutex.xml b/doc/classes/Mutex.xml
index 2de1f71867..f5f6308401 100644
--- a/doc/classes/Mutex.xml
+++ b/doc/classes/Mutex.xml
@@ -7,7 +7,7 @@
A synchronization mutex (mutual exclusion). This is used to synchronize multiple [Thread]s, and is equivalent to a binary [Semaphore]. It guarantees that only one thread can ever acquire the lock at a time. A mutex can be used to protect a critical section; however, be careful to avoid deadlocks.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/threads/using_multiple_threads.html</link>
+ <link title="Using multiple threads">https://docs.godotengine.org/en/latest/tutorials/threads/using_multiple_threads.html</link>
</tutorials>
<methods>
<method name="lock">
diff --git a/doc/classes/NetworkedMultiplayerPeer.xml b/doc/classes/NetworkedMultiplayerPeer.xml
index ff97ea926d..7e2a9af59f 100644
--- a/doc/classes/NetworkedMultiplayerPeer.xml
+++ b/doc/classes/NetworkedMultiplayerPeer.xml
@@ -7,7 +7,7 @@
Manages the connection to network peers. Assigns unique IDs to each client connected to the server.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/networking/high_level_multiplayer.html</link>
+ <link title="High-level multiplayer">https://docs.godotengine.org/en/latest/tutorials/networking/high_level_multiplayer.html</link>
</tutorials>
<methods>
<method name="get_connection_status" qualifiers="const">
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 8f66c9df38..b342fc0813 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -17,7 +17,7 @@
[b]Networking with nodes:[/b] After connecting to a server (or making one, see [NetworkedMultiplayerENet]), it is possible to use the built-in RPC (remote procedure call) system to communicate over the network. By calling [method rpc] with a method name, it will be called locally and in all connected peers (peers = clients and the server that accepts connections). To identify which node receives the RPC call, Godot will use its [NodePath] (make sure node names are the same on all peers). Also, take a look at the high-level networking tutorial and corresponding demos.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/getting_started/step_by_step/scenes_and_nodes.html</link>
+ <link title="Scenes and nodes">https://docs.godotengine.org/en/latest/getting_started/step_by_step/scenes_and_nodes.html</link>
</tutorials>
<methods>
<method name="_enter_tree" qualifiers="virtual">
@@ -194,6 +194,7 @@
Finds a descendant of this node whose name matches [code]mask[/code] as in [method String.match] (i.e. case-sensitive, but [code]"*"[/code] matches zero or more characters and [code]"?"[/code] matches any single character except [code]"."[/code]).
[b]Note:[/b] It does not match against the full path, just against individual node names.
If [code]owned[/code] is [code]true[/code], this method only finds nodes whose owner is this node. This is especially important for scenes instantiated through a script, because those scenes don't have an owner.
+ [b]Note:[/b] As this method walks through all the descendants of the node, it is the slowest way to get a reference to another node. Whenever possible, consider using [method get_node] instead. To avoid using [method find_node] too often, consider caching the node reference into a variable.
</description>
</method>
<method name="find_parent" qualifiers="const">
@@ -204,6 +205,7 @@
<description>
Finds the first parent of the current node whose name matches [code]mask[/code] as in [method String.match] (i.e. case-sensitive, but [code]"*"[/code] matches zero or more characters and [code]"?"[/code] matches any single character except [code]"."[/code]).
[b]Note:[/b] It does not match against the full path, just against individual node names.
+ [b]Note:[/b] As this method walks upwards in the scene tree, it can be slow in large, deeply nested scene trees. Whenever possible, consider using [method get_node] instead. To avoid using [method find_parent] too often, consider caching the node reference into a variable.
</description>
</method>
<method name="get_child" qualifiers="const">
@@ -213,6 +215,7 @@
</argument>
<description>
Returns a child node by its index (see [method get_child_count]). This method is often used for iterating all children of a node.
+ Negative indices access the children from the last one.
To access a child node via its name, use [method get_node].
</description>
</method>
diff --git a/doc/classes/Node2D.xml b/doc/classes/Node2D.xml
index d29c556216..987a18f367 100644
--- a/doc/classes/Node2D.xml
+++ b/doc/classes/Node2D.xml
@@ -7,7 +7,7 @@
A 2D game object, with a transform (position, rotation, and scale). All 2D nodes, including physics objects and sprites, inherit from Node2D. Use Node2D as a parent node to move, scale and rotate children in a 2D project. Also gives control of the node's render order.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/2d/custom_drawing_in_2d.html</link>
+ <link title="Custom drawing in 2D">https://docs.godotengine.org/en/latest/tutorials/2d/custom_drawing_in_2d.html</link>
</tutorials>
<methods>
<method name="apply_scale">
diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml
index 02b319fb5a..1ef875f606 100644
--- a/doc/classes/Node3D.xml
+++ b/doc/classes/Node3D.xml
@@ -9,7 +9,7 @@
[b]Note:[/b] Unless otherwise specified, all methods that have angle parameters must have angles specified as [i]radians[/i]. To convert degrees to radians, use [method @GDScript.deg2rad].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/introduction_to_3d.html</link>
+ <link title="Introduction to 3D">https://docs.godotengine.org/en/latest/tutorials/3d/introduction_to_3d.html</link>
</tutorials>
<methods>
<method name="force_update_transform">
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index 077067a0f4..2395ccd211 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -495,7 +495,7 @@
<description>
Translates a message using translation catalogs configured in the Project Settings. An additional context could be used to specify the translation context.
Only works if message translation is enabled (which it is by default), otherwise it returns the [code]message[/code] unchanged. See [method set_message_translation].
- See <link>https://docs.godotengine.org/en/latest/tutorials/i18n/internationalizing_games.html</link> for examples of the usage of this method.
+ See [url=https://docs.godotengine.org/en/latest/tutorials/i18n/internationalizing_games.html]Internationalizing games[/url] for examples of the usage of this method.
</description>
</method>
<method name="tr_n" qualifiers="const">
@@ -514,7 +514,7 @@
Only works if message translation is enabled (which it is by default), otherwise it returns the [code]message[/code] or [code]plural_message[/code] unchanged. See [method set_message_translation].
The number [code]n[/code] is the number or quantity of the plural object. It will be used to guide the translation system to fetch the correct plural form for the selected language.
[b]Note:[/b] Negative and floating-point values usually represent physical entities for which singular and plural don't clearly apply. In such cases, use [method tr].
- See <link>https://docs.godotengine.org/en/latest/tutorials/i18n/localization_using_gettext.html</link> for examples of the usage of this method.
+ See [url=https://docs.godotengine.org/en/latest/tutorials/i18n/localization_using_gettext.html]Localization using gettext[/url] for examples of the usage of this method.
</description>
</method>
</methods>
diff --git a/doc/classes/OmniLight3D.xml b/doc/classes/OmniLight3D.xml
index 000d67e691..dfcb19a287 100644
--- a/doc/classes/OmniLight3D.xml
+++ b/doc/classes/OmniLight3D.xml
@@ -7,7 +7,7 @@
An Omnidirectional light is a type of [Light3D] that emits light in all directions. The light is attenuated by distance and this attenuation can be configured by changing its energy, radius, and attenuation parameters.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
+ <link title="3D lights and shadows">https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml
index 39d974ec47..8c4bbd6716 100644
--- a/doc/classes/OptionButton.xml
+++ b/doc/classes/OptionButton.xml
@@ -217,7 +217,7 @@
<argument index="0" name="index" type="int">
</argument>
<description>
- Emitted the when user navigates to an item using the [code]ui_up[/code] or [code]ui_down[/code] actions. The index of the item selected is passed as argument.
+ Emitted when the user navigates to an item using the [code]ui_up[/code] or [code]ui_down[/code] actions. The index of the item selected is passed as argument.
</description>
</signal>
<signal name="item_selected">
diff --git a/doc/classes/PackedByteArray.xml b/doc/classes/PackedByteArray.xml
index 08f8558881..b1c4e54854 100644
--- a/doc/classes/PackedByteArray.xml
+++ b/doc/classes/PackedByteArray.xml
@@ -68,14 +68,28 @@
<return type="String">
</return>
<description>
- Returns a copy of the array's contents as [String]. Fast alternative to [method get_string_from_utf8] if the content is ASCII-only. Unlike the UTF-8 function this function maps every byte to a character in the array. Multibyte sequences will not be interpreted correctly. For parsing user input always use [method get_string_from_utf8].
+ Converts ASCII/Latin-1 encoded array to [String]. Fast alternative to [method get_string_from_utf8] if the content is ASCII/Latin-1 only. Unlike the UTF-8 function this function maps every byte to a character in the array. Multibyte sequences will not be interpreted correctly. For parsing user input always use [method get_string_from_utf8].
+ </description>
+ </method>
+ <method name="get_string_from_utf16">
+ <return type="String">
+ </return>
+ <description>
+ Converts UTF-16 encoded array to [String]. If the BOM is missing, system endianness is assumed. Returns empty string if source array is not vaild UTF-16 string.
+ </description>
+ </method>
+ <method name="get_string_from_utf32">
+ <return type="String">
+ </return>
+ <description>
+ Converts UTF-32 encoded array to [String]. System endianness is assumed. Returns empty string if source array is not vaild UTF-32 string.
</description>
</method>
<method name="get_string_from_utf8">
<return type="String">
</return>
<description>
- Returns a copy of the array's contents as [String]. Slower than [method get_string_from_ascii] but supports UTF-8 encoded data. Use this function if you are unsure about the source of the data. For user input this function should always be preferred.
+ Converts UTF-8 encoded array to [String]. Slower than [method get_string_from_ascii] but supports UTF-8 encoded data. Use this function if you are unsure about the source of the data. For user input this function should always be preferred. Returns empty string if source array is not vaild UTF-8 string.
</description>
</method>
<method name="has">
diff --git a/doc/classes/PhysicsBody2D.xml b/doc/classes/PhysicsBody2D.xml
index 6afbd1ee8e..ca42f5801a 100644
--- a/doc/classes/PhysicsBody2D.xml
+++ b/doc/classes/PhysicsBody2D.xml
@@ -7,7 +7,7 @@
PhysicsBody2D is an abstract base class for implementing a physics body. All *Body2D types inherit from it.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
+ <link title="Physics introduction">https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
</tutorials>
<methods>
<method name="add_collision_exception_with">
@@ -80,10 +80,10 @@
<member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
The physics layers this area is in.
Collidable objects can exist in any of 32 different layers. These layers work like a tagging system, and are not visual. A collidable can use these layers to select with which objects it can collide, using the [member collision_mask] property.
- A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A.
+ A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this area scans for collisions.
+ The physics layers this area scans for collisions. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="input_pickable" type="bool" setter="set_pickable" getter="is_pickable" override="true" default="false" />
<member name="layers" type="int" setter="_set_layers" getter="_get_layers">
diff --git a/doc/classes/PhysicsBody3D.xml b/doc/classes/PhysicsBody3D.xml
index 2301a07a5c..7de65603f9 100644
--- a/doc/classes/PhysicsBody3D.xml
+++ b/doc/classes/PhysicsBody3D.xml
@@ -7,7 +7,7 @@
PhysicsBody3D is an abstract base class for implementing a physics body. All *Body types inherit from it.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
+ <link title="Physics introduction">https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
</tutorials>
<methods>
<method name="add_collision_exception_with">
@@ -80,10 +80,10 @@
<member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
The physics layers this area is in.
Collidable objects can exist in any of 32 different layers. These layers work like a tagging system, and are not visual. A collidable can use these layers to select with which objects it can collide, using the [member collision_mask] property.
- A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A.
+ A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this area scans for collisions.
+ The physics layers this area scans for collisions. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
</members>
<constants>
diff --git a/doc/classes/PhysicsDirectBodyState2D.xml b/doc/classes/PhysicsDirectBodyState2D.xml
index 30519e11be..dfc0ab909a 100644
--- a/doc/classes/PhysicsDirectBodyState2D.xml
+++ b/doc/classes/PhysicsDirectBodyState2D.xml
@@ -7,7 +7,7 @@
Provides direct access to a physics body in the [PhysicsServer2D], allowing safe changes to physics properties. This object is passed via the direct state callback of rigid/character bodies, and is intended for changing the direct state of that body. See [method RigidBody2D._integrate_forces].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
+ <link title="Ray-casting">https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
</tutorials>
<methods>
<method name="add_central_force">
diff --git a/doc/classes/PhysicsDirectSpaceState2D.xml b/doc/classes/PhysicsDirectSpaceState2D.xml
index d85d7794dd..676e33601a 100644
--- a/doc/classes/PhysicsDirectSpaceState2D.xml
+++ b/doc/classes/PhysicsDirectSpaceState2D.xml
@@ -7,7 +7,7 @@
Direct access object to a space in the [PhysicsServer2D]. It's used mainly to do queries against objects and areas residing in a given space.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
+ <link title="Ray-Casting">https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
</tutorials>
<methods>
<method name="cast_motion">
diff --git a/doc/classes/PhysicsDirectSpaceState3D.xml b/doc/classes/PhysicsDirectSpaceState3D.xml
index ea094dcd90..789e8cc731 100644
--- a/doc/classes/PhysicsDirectSpaceState3D.xml
+++ b/doc/classes/PhysicsDirectSpaceState3D.xml
@@ -7,7 +7,7 @@
Direct access object to a space in the [PhysicsServer3D]. It's used mainly to do queries against objects and areas residing in a given space.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
+ <link title="Ray-casting">https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
</tutorials>
<methods>
<method name="cast_motion">
diff --git a/doc/classes/PhysicsShapeQueryParameters2D.xml b/doc/classes/PhysicsShapeQueryParameters2D.xml
index 63e13954ab..93ca684b95 100644
--- a/doc/classes/PhysicsShapeQueryParameters2D.xml
+++ b/doc/classes/PhysicsShapeQueryParameters2D.xml
@@ -18,7 +18,7 @@
If [code]true[/code], the query will take [PhysicsBody2D]s into account.
</member>
<member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="2147483647">
- The physics layer(s) the query will take into account (as a bitmask).
+ The physics layer(s) the query will take into account (as a bitmask). See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[ ]">
The list of objects or object [RID]s that will be excluded from collisions.
diff --git a/doc/classes/PhysicsShapeQueryParameters3D.xml b/doc/classes/PhysicsShapeQueryParameters3D.xml
index f4191d4862..167fb31bb3 100644
--- a/doc/classes/PhysicsShapeQueryParameters3D.xml
+++ b/doc/classes/PhysicsShapeQueryParameters3D.xml
@@ -18,7 +18,7 @@
If [code]true[/code], the query will take [PhysicsBody3D]s into account.
</member>
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="2147483647">
- The physics layer(s) the query will take into account (as a bitmask).
+ The physics layer(s) the query will take into account (as a bitmask). See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[ ]">
The list of objects or object [RID]s that will be excluded from collisions.
diff --git a/doc/classes/Plane.xml b/doc/classes/Plane.xml
index ce0680523c..d420e6ccdc 100644
--- a/doc/classes/Plane.xml
+++ b/doc/classes/Plane.xml
@@ -7,7 +7,7 @@
Plane represents a normalized plane equation. Basically, "normal" is the normal of the plane (a,b,c normalized), and "d" is the distance from the origin to the plane (in the direction of "normal"). "Over" or "Above" the plane is considered the side of the plane towards where the normal is pointing.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
+ <link title="Math tutorial index">https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
</tutorials>
<methods>
<method name="Plane">
diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml
index ce55c90c68..2af0f500a0 100644
--- a/doc/classes/PopupMenu.xml
+++ b/doc/classes/PopupMenu.xml
@@ -5,6 +5,8 @@
</brief_description>
<description>
[PopupMenu] is a [Control] that displays a list of options. They are popular in toolbars or context menus.
+ The size of a [PopupMenu] can be limited by using [member Window.max_size]. If the height of the list of items is larger than the maximum height of the [PopupMenu], a [ScrollContainer] within the popup will allow the user to scroll the contents.
+ If no maximum size is set, or if it is set to 0, the [PopupMenu] height will be limited by its parent rect.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 793249afc5..38d65f6338 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -92,9 +92,12 @@
</argument>
<argument index="1" name="replace_files" type="bool" default="true">
</argument>
+ <argument index="2" name="offset" type="int" default="0">
+ </argument>
<description>
Loads the contents of the .pck or .zip file specified by [code]pack[/code] into the resource filesystem ([code]res://[/code]). Returns [code]true[/code] on success.
[b]Note:[/b] If a file from [code]pack[/code] shares the same path as a file already in the resource filesystem, any attempts to load that file will use the file from [code]pack[/code] unless [code]replace_files[/code] is set to [code]false[/code].
+ [b]Note:[/b] The optional [code]offset[/code] parameter can be used to specify the offset in bytes to the start of the resource pack. This is only supported for .pck files.
</description>
</method>
<method name="localize_path" qualifiers="const">
@@ -205,7 +208,8 @@
Icon set in [code].icns[/code] format used on macOS to set the game's icon. This is done automatically on start by calling [method DisplayServer.set_native_icon].
</member>
<member name="application/config/name" type="String" setter="" getter="" default="&quot;&quot;">
- The project's name. It is used both by the Project Manager and by exporters. The project name can be translated by translating its value in localization files.
+ The project's name. It is used both by the Project Manager and by exporters. The project name can be translated by translating its value in localization files. The window title will be set to match the project name automatically on startup.
+ [b]Note:[/b] Changing this value will also change the user data folder's path if [member application/config/use_custom_user_dir] is [code]false[/code]. After renaming the project, you will no longer be able to access existing data in [code]user://[/code] unless you rename the old folder to match the new project name. See [url=https://docs.godotengine.org/en/latest/tutorials/io/data_paths.html]Data paths[/url] in the documentation for more information.
</member>
<member name="application/config/project_settings_override" type="String" setter="" getter="" default="&quot;&quot;">
Specifies a file to override project settings. For example: [code]user://custom_settings.cfg[/code].
@@ -1038,6 +1042,9 @@
<member name="rendering/quality/glow/upscale_mode.mobile" type="int" setter="" getter="" default="0">
Lower-end override for [member rendering/quality/glow/upscale_mode] on mobile devices, due to performance concerns or driver support.
</member>
+ <member name="rendering/quality/glow/use_high_quality" type="bool" setter="" getter="" default="false">
+ Takes more samples during downsample pass of glow. This ensures that single pixels are captured by glow which makes the glow look smoother and more stable during movement. However, it is very expensive and makes the glow post process take twice as long.
+ </member>
<member name="rendering/quality/intended_usage/framebuffer_allocation" type="int" setter="" getter="" default="2">
Strategy used for framebuffer allocation. The simpler it is, the less resources it uses (but the less features it supports). If set to "2D Without Sampling" or "3D Without Effects", sample buffers will not be allocated. This means [code]SCREEN_TEXTURE[/code] and [code]DEPTH_TEXTURE[/code] will not be available in shaders and post-processing effects will not be available in the [Environment].
</member>
@@ -1158,6 +1165,16 @@
<member name="rendering/threads/thread_model" type="int" setter="" getter="" default="1">
Thread model for rendering. Rendering on a thread can vastly improve performance, but synchronizing to the main thread can cause a bit more jitter.
</member>
+ <member name="rendering/volumetric_fog/directional_shadow_shrink" type="int" setter="" getter="" default="512">
+ </member>
+ <member name="rendering/volumetric_fog/positional_shadow_shrink" type="int" setter="" getter="" default="512">
+ </member>
+ <member name="rendering/volumetric_fog/use_filter" type="int" setter="" getter="" default="0">
+ </member>
+ <member name="rendering/volumetric_fog/volume_depth" type="int" setter="" getter="" default="128">
+ </member>
+ <member name="rendering/volumetric_fog/volume_size" type="int" setter="" getter="" default="64">
+ </member>
<member name="rendering/vram_compression/import_bptc" type="bool" setter="" getter="" default="false">
If [code]true[/code], the texture importer will import VRAM-compressed textures using the BPTC algorithm. This texture compression algorithm is only supported on desktop platforms, and only when using the Vulkan renderer.
</member>
diff --git a/doc/classes/Quat.xml b/doc/classes/Quat.xml
index 730edb00d9..2218852dae 100644
--- a/doc/classes/Quat.xml
+++ b/doc/classes/Quat.xml
@@ -9,7 +9,7 @@
Due to its compactness and the way it is stored in memory, certain operations (obtaining axis-angle and performing SLERP, in particular) are more efficient and robust against floating-point errors.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html#interpolating-with-quaternions</link>
+ <link title="Using 3D transforms">https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html#interpolating-with-quaternions</link>
</tutorials>
<methods>
<method name="Quat">
diff --git a/doc/classes/RayCast2D.xml b/doc/classes/RayCast2D.xml
index 6a11630c0e..db4b9a0383 100644
--- a/doc/classes/RayCast2D.xml
+++ b/doc/classes/RayCast2D.xml
@@ -11,7 +11,7 @@
RayCast2D calculates intersection every physics frame (see [Node]), and the result is cached so it can be used later until the next frame. If multiple queries are required between physics frames (or during the same frame) use [method force_raycast_update] after adjusting the raycast.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
+ <link title="Ray-casting">https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
</tutorials>
<methods>
<method name="add_exception">
@@ -133,7 +133,7 @@
If [code]true[/code], collision with [PhysicsBody2D]s will be reported.
</member>
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The ray's collision mask. Only objects in at least one collision layer enabled in the mask will be detected.
+ The ray's collision mask. Only objects in at least one collision layer enabled in the mask will be detected. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true">
If [code]true[/code], collisions will be reported.
diff --git a/doc/classes/RayCast3D.xml b/doc/classes/RayCast3D.xml
index e7ee1d284f..1e61664a7d 100644
--- a/doc/classes/RayCast3D.xml
+++ b/doc/classes/RayCast3D.xml
@@ -11,7 +11,7 @@
RayCast3D calculates intersection every physics frame (see [Node]), and the result is cached so it can be used later until the next frame. If multiple queries are required between physics frames (or during the same frame), use [method force_raycast_update] after adjusting the raycast.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
+ <link title="Ray-casting">https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
</tutorials>
<methods>
<method name="add_exception">
@@ -136,7 +136,7 @@
If [code]true[/code], collision with [PhysicsBody3D]s will be reported.
</member>
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The ray's collision mask. Only objects in at least one collision layer enabled in the mask will be detected.
+ The ray's collision mask. Only objects in at least one collision layer enabled in the mask will be detected. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true">
If [code]true[/code], collisions will be reported.
diff --git a/doc/classes/Rect2.xml b/doc/classes/Rect2.xml
index 8599aad95e..fe05f14fa1 100644
--- a/doc/classes/Rect2.xml
+++ b/doc/classes/Rect2.xml
@@ -8,7 +8,7 @@
It uses floating point coordinates.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
+ <link title="Math tutorial index">https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
</tutorials>
<methods>
<method name="Rect2">
diff --git a/doc/classes/Rect2i.xml b/doc/classes/Rect2i.xml
index 7362580c02..2fdfe7c24b 100644
--- a/doc/classes/Rect2i.xml
+++ b/doc/classes/Rect2i.xml
@@ -8,7 +8,7 @@
It uses integer coordinates.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
+ <link title="Math tutorial index">https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
</tutorials>
<methods>
<method name="Rect2i">
diff --git a/doc/classes/ReflectionProbe.xml b/doc/classes/ReflectionProbe.xml
index 07d7b646a1..5458b496da 100644
--- a/doc/classes/ReflectionProbe.xml
+++ b/doc/classes/ReflectionProbe.xml
@@ -8,7 +8,7 @@
The [ReflectionProbe] is used to create high-quality reflections at the cost of performance. It can be combined with [GIProbe]s and Screen Space Reflections to achieve high quality reflections. [ReflectionProbe]s render all objects within their [member cull_mask], so updating them can be quite expensive. It is best to update them once with the important static objects and then leave them.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/reflection_probes.html</link>
+ <link title="Reflection probes">https://docs.godotengine.org/en/latest/tutorials/3d/reflection_probes.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 85eaac454f..9c8c964967 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -15,7 +15,7 @@
In 2D, all visible objects are some form of canvas item. In order to be visible, a canvas item needs to be the child of a canvas attached to a viewport, or it needs to be the child of another canvas item that is eventually attached to the canvas.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/optimization/using_servers.html</link>
+ <link title="Optimization using Servers">https://docs.godotengine.org/en/latest/tutorials/optimization/using_servers.html</link>
</tutorials>
<methods>
<method name="black_bars_set_images">
@@ -690,52 +690,19 @@
</argument>
<argument index="1" name="enable" type="bool">
</argument>
- <argument index="2" name="color" type="Color">
- </argument>
- <argument index="3" name="sun_color" type="Color">
- </argument>
- <argument index="4" name="sun_amount" type="float">
- </argument>
- <description>
- Sets the variables to be used with the scene fog. See [Environment] for more details.
- </description>
- </method>
- <method name="environment_set_fog_depth">
- <return type="void">
- </return>
- <argument index="0" name="env" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
+ <argument index="2" name="light_color" type="Color">
</argument>
- <argument index="2" name="depth_begin" type="float">
+ <argument index="3" name="light_energy" type="float">
</argument>
- <argument index="3" name="depth_end" type="float">
- </argument>
- <argument index="4" name="depth_curve" type="float">
- </argument>
- <argument index="5" name="transmit" type="bool">
- </argument>
- <argument index="6" name="transmit_curve" type="float">
- </argument>
- <description>
- Sets the variables to be used with the fog depth effect. See [Environment] for more details.
- </description>
- </method>
- <method name="environment_set_fog_height">
- <return type="void">
- </return>
- <argument index="0" name="env" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
+ <argument index="4" name="sun_scatter" type="float">
</argument>
- <argument index="2" name="min_height" type="float">
+ <argument index="5" name="density" type="float">
</argument>
- <argument index="3" name="max_height" type="float">
+ <argument index="6" name="height" type="float">
</argument>
- <argument index="4" name="height_curve" type="float">
+ <argument index="7" name="height_density" type="float">
</argument>
<description>
- Sets the variables to be used with the fog height effect. See [Environment] for more details.
</description>
</method>
<method name="environment_set_glow">
@@ -3252,9 +3219,9 @@
<constant name="LIGHT_PARAM_SHADOW_BLUR" value="16" enum="LightParam">
Blurs the edges of the shadow. Can be used to hide pixel artifacts in low resolution shadow maps. A high value can make shadows appear grainy and can cause other unwanted artifacts. Try to keep as near default as possible.
</constant>
- <constant name="LIGHT_PARAM_TRANSMITTANCE_BIAS" value="17" enum="LightParam">
+ <constant name="LIGHT_PARAM_TRANSMITTANCE_BIAS" value="18" enum="LightParam">
</constant>
- <constant name="LIGHT_PARAM_MAX" value="18" enum="LightParam">
+ <constant name="LIGHT_PARAM_MAX" value="19" enum="LightParam">
Represents the size of the [enum LightParam] enum.
</constant>
<constant name="LIGHT_BAKE_DISABLED" value="0" enum="LightBakeMode">
diff --git a/doc/classes/RichTextEffect.xml b/doc/classes/RichTextEffect.xml
index 34431c5153..726b26fbc7 100644
--- a/doc/classes/RichTextEffect.xml
+++ b/doc/classes/RichTextEffect.xml
@@ -13,8 +13,8 @@
[b]Note:[/b] As soon as a [RichTextLabel] contains at least one [RichTextEffect], it will continuously process the effect unless the project is paused. This may impact battery life negatively.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/gui/bbcode_in_richtextlabel.html</link>
- <link>https://github.com/Eoin-ONeill-Yokai/Godot-Rich-Text-Effect-Test-Project</link>
+ <link title="BBCode in RichTextLabel">https://docs.godotengine.org/en/latest/tutorials/gui/bbcode_in_richtextlabel.html</link>
+ <link title="RichTextEffect test project (third-party)">https://github.com/Eoin-ONeill-Yokai/Godot-Rich-Text-Effect-Test-Project</link>
</tutorials>
<methods>
<method name="_process_custom_fx" qualifiers="virtual">
diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml
index a1c4fcc53c..dc3c7c7dc0 100644
--- a/doc/classes/RichTextLabel.xml
+++ b/doc/classes/RichTextLabel.xml
@@ -9,7 +9,7 @@
[b]Note:[/b] Unlike [Label], RichTextLabel doesn't have a [i]property[/i] to horizontally align text to the center. Instead, enable [member bbcode_enabled] and surround the text in a [code][center][/code] tag as follows: [code][center]Example[/center][/code]. There is currently no built-in way to vertically align text either, but this can be emulated by relying on anchors/containers and the [member fit_content_height] property.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/gui/bbcode_in_richtextlabel.html</link>
+ <link title="BBCode in RichTextLabel">https://docs.godotengine.org/en/latest/tutorials/gui/bbcode_in_richtextlabel.html</link>
</tutorials>
<methods>
<method name="add_image">
diff --git a/doc/classes/RigidBody2D.xml b/doc/classes/RigidBody2D.xml
index a7efba518c..f3d43b193e 100644
--- a/doc/classes/RigidBody2D.xml
+++ b/doc/classes/RigidBody2D.xml
@@ -9,6 +9,7 @@
[b]Note:[/b] You should not change a RigidBody2D's [code]position[/code] or [code]linear_velocity[/code] every frame or even very often. If you need to directly affect the body's state, use [method _integrate_forces], which allows you to directly access the physics state.
Please also keep in mind that physics bodies manage their own transform which overwrites the ones you set. So any direct or indirect transformation (including scaling of the node or its parent) will be visible in the editor only, and immediately reset at runtime.
If you need to override the default physics behavior or add a transformation at runtime, you can write a custom force integration. See [member custom_integrator].
+ The center of mass is always located at the node's origin without taking into account the [CollisionShape2D] centroid offsets.
</description>
<tutorials>
</tutorials>
@@ -128,6 +129,7 @@
</member>
<member name="can_sleep" type="bool" setter="set_can_sleep" getter="is_able_to_sleep" default="true">
If [code]true[/code], the body can enter sleep mode when there is no movement. See [member sleeping].
+ [b]Note:[/b] A RigidBody2D will never enter sleep mode automatically if its [member mode] is [constant MODE_CHARACTER]. It can still be put to sleep manually by setting its [member sleeping] property to [code]true[/code].
</member>
<member name="contact_monitor" type="bool" setter="set_contact_monitor" getter="is_contact_monitor_enabled" default="false">
If [code]true[/code], the body will emit signals when it collides with another RigidBody2D. See also [member contacts_reported].
diff --git a/doc/classes/RigidBody3D.xml b/doc/classes/RigidBody3D.xml
index 933885ba77..e9ebf33aa7 100644
--- a/doc/classes/RigidBody3D.xml
+++ b/doc/classes/RigidBody3D.xml
@@ -8,9 +8,10 @@
A RigidBody3D has 4 behavior [member mode]s: Rigid, Static, Character, and Kinematic.
[b]Note:[/b] Don't change a RigidBody3D's position every frame or very often. Sporadic changes work fine, but physics runs at a different granularity (fixed Hz) than usual rendering (process callback) and maybe even in a separate thread, so changing this from a process loop may result in strange behavior. If you need to directly affect the body's state, use [method _integrate_forces], which allows you to directly access the physics state.
If you need to override the default physics behavior, you can write a custom force integration function. See [member custom_integrator].
+ With Bullet physics (the default), the center of mass is the RigidBody3D center. With GodotPhysics, the center of mass is the average of the [CollisionShape3D] centers.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
+ <link title="Physics introduction">https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
</tutorials>
<methods>
<method name="_integrate_forces" qualifiers="virtual">
@@ -155,6 +156,7 @@
</member>
<member name="can_sleep" type="bool" setter="set_can_sleep" getter="is_able_to_sleep" default="true">
If [code]true[/code], the body can enter sleep mode when there is no movement. See [member sleeping].
+ [b]Note:[/b] A RigidBody3D will never enter sleep mode automatically if its [member mode] is [constant MODE_CHARACTER]. It can still be put to sleep manually by setting its [member sleeping] property to [code]true[/code].
</member>
<member name="contact_monitor" type="bool" setter="set_contact_monitor" getter="is_contact_monitor_enabled" default="false">
If [code]true[/code], the RigidBody3D will emit signals when it collides with another RigidBody3D. See also [member contacts_reported].
diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml
index 00ca5c6e9f..4ea457047f 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -9,8 +9,8 @@
[SceneTree] is the default [MainLoop] implementation used by scenes, and is thus in charge of the game loop.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/getting_started/step_by_step/scene_tree.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/viewports/multiple_resolutions.html</link>
+ <link title="SceneTree">https://docs.godotengine.org/en/latest/getting_started/step_by_step/scene_tree.html</link>
+ <link title="Multiple resolutions">https://docs.godotengine.org/en/latest/tutorials/viewports/multiple_resolutions.html</link>
</tutorials>
<methods>
<method name="call_group" qualifiers="vararg">
diff --git a/doc/classes/Script.xml b/doc/classes/Script.xml
index 0d94453e52..56272760bd 100644
--- a/doc/classes/Script.xml
+++ b/doc/classes/Script.xml
@@ -8,7 +8,7 @@
The [code]new[/code] method of a script subclass creates a new instance. [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/getting_started/step_by_step/scripting.html</link>
+ <link title="Scripting">https://docs.godotengine.org/en/latest/getting_started/step_by_step/scripting.html</link>
</tutorials>
<methods>
<method name="can_instance" qualifiers="const">
diff --git a/doc/classes/Semaphore.xml b/doc/classes/Semaphore.xml
index c9745acfcd..f311e1c72f 100644
--- a/doc/classes/Semaphore.xml
+++ b/doc/classes/Semaphore.xml
@@ -7,7 +7,7 @@
A synchronization semaphore which can be used to synchronize multiple [Thread]s. Initialized to zero on creation. Be careful to avoid deadlocks. For a binary version, see [Mutex].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/threads/using_multiple_threads.html</link>
+ <link title="Using multiple threads">https://docs.godotengine.org/en/latest/tutorials/threads/using_multiple_threads.html</link>
</tutorials>
<methods>
<method name="post">
diff --git a/doc/classes/Shader.xml b/doc/classes/Shader.xml
index 109c500a63..a717eba438 100644
--- a/doc/classes/Shader.xml
+++ b/doc/classes/Shader.xml
@@ -7,8 +7,8 @@
This class allows you to define a custom shader program that can be used by a [ShaderMaterial]. Shaders allow you to write your own custom behavior for rendering objects or updating particle information. For a detailed explanation and usage, please see the tutorials linked below.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/shading/index.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/shading/your_first_shader/what_are_shaders.html</link>
+ <link title="Shading tutorial index">https://docs.godotengine.org/en/latest/tutorials/shading/index.html</link>
+ <link title="What are shaders?">https://docs.godotengine.org/en/latest/tutorials/shading/your_first_shader/what_are_shaders.html</link>
</tutorials>
<methods>
<method name="get_default_texture_param" qualifiers="const">
diff --git a/doc/classes/ShaderMaterial.xml b/doc/classes/ShaderMaterial.xml
index 7e0e1ce831..b1748703ff 100644
--- a/doc/classes/ShaderMaterial.xml
+++ b/doc/classes/ShaderMaterial.xml
@@ -7,7 +7,7 @@
A material that uses a custom [Shader] program to render either items to screen or process particles. You can create multiple materials for the same shader but configure different values for the uniforms defined in the shader.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/shading/index.html</link>
+ <link title="Shading tutorial index">https://docs.godotengine.org/en/latest/tutorials/shading/index.html</link>
</tutorials>
<methods>
<method name="get_shader_param" qualifiers="const">
diff --git a/doc/classes/Shape2D.xml b/doc/classes/Shape2D.xml
index 5f41d05816..65a37314f6 100644
--- a/doc/classes/Shape2D.xml
+++ b/doc/classes/Shape2D.xml
@@ -7,7 +7,7 @@
Base class for all 2D shapes. All 2D shape types inherit from this.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
+ <link title="Physics introduction">https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
</tutorials>
<methods>
<method name="collide">
diff --git a/doc/classes/Shape3D.xml b/doc/classes/Shape3D.xml
index 1af6550dc5..2d8bb5d051 100644
--- a/doc/classes/Shape3D.xml
+++ b/doc/classes/Shape3D.xml
@@ -7,7 +7,7 @@
Base class for all 3D shape resources. Nodes that inherit from this can be used as shapes for a [PhysicsBody3D] or [Area3D] objects.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
+ <link title="Physics introduction">https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/Skeleton2D.xml b/doc/classes/Skeleton2D.xml
index e1b7d60763..0ddbac9ba4 100644
--- a/doc/classes/Skeleton2D.xml
+++ b/doc/classes/Skeleton2D.xml
@@ -7,7 +7,7 @@
Skeleton2D parents a hierarchy of [Bone2D] objects. It is a requirement of [Bone2D]. Skeleton2D holds a reference to the rest pose of its children and acts as a single point of access to its bones.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/animation/2d_skeletons.html</link>
+ <link title="2D skeletons">https://docs.godotengine.org/en/latest/tutorials/animation/2d_skeletons.html</link>
</tutorials>
<methods>
<method name="get_bone">
diff --git a/doc/classes/SoftBody3D.xml b/doc/classes/SoftBody3D.xml
index 24d6609900..d3ab955570 100644
--- a/doc/classes/SoftBody3D.xml
+++ b/doc/classes/SoftBody3D.xml
@@ -7,7 +7,7 @@
A deformable physics body. Used to create elastic or deformable objects such as cloth, rubber, or other flexible materials.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/soft_body.html</link>
+ <link title="SoftBody">https://docs.godotengine.org/en/latest/tutorials/physics/soft_body.html</link>
</tutorials>
<methods>
<method name="add_collision_exception_with">
@@ -82,10 +82,10 @@
<member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
The physics layers this SoftBody3D is in.
Collidable objects can exist in any of 32 different layers. These layers work like a tagging system, and are not visual. A collidable can use these layers to select with which objects it can collide, using the collision_mask property.
- A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A.
+ A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this SoftBody3D scans for collisions.
+ The physics layers this SoftBody3D scans for collisions. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="damping_coefficient" type="float" setter="set_damping_coefficient" getter="get_damping_coefficient" default="0.01">
</member>
diff --git a/doc/classes/SpotLight3D.xml b/doc/classes/SpotLight3D.xml
index 423633e583..fc849baa8d 100644
--- a/doc/classes/SpotLight3D.xml
+++ b/doc/classes/SpotLight3D.xml
@@ -7,7 +7,7 @@
A Spotlight is a type of [Light3D] node that emits lights in a specific direction, in the shape of a cone. The light is attenuated through the distance. This attenuation can be configured by changing the energy, radius and attenuation parameters of [Light3D].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
+ <link title="3D lights and shadows">https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/SpringArm3D.xml b/doc/classes/SpringArm3D.xml
index 15caff9eeb..3ffdbebae8 100644
--- a/doc/classes/SpringArm3D.xml
+++ b/doc/classes/SpringArm3D.xml
@@ -47,7 +47,7 @@
</methods>
<members>
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The layers against which the collision check shall be done.
+ The layers against which the collision check shall be done. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.01">
When the collision check is made, a candidate length for the SpringArm3D is given.
diff --git a/doc/classes/Sprite2D.xml b/doc/classes/Sprite2D.xml
index 92f561d7b5..f218631038 100644
--- a/doc/classes/Sprite2D.xml
+++ b/doc/classes/Sprite2D.xml
@@ -44,10 +44,10 @@
If [code]true[/code], texture is flipped vertically.
</member>
<member name="frame" type="int" setter="set_frame" getter="get_frame" default="0">
- Current frame to display from sprite sheet. [member vframes] or [member hframes] must be greater than 1.
+ Current frame to display from sprite sheet. [member hframes] or [member vframes] must be greater than 1.
</member>
<member name="frame_coords" type="Vector2" setter="set_frame_coords" getter="get_frame_coords" default="Vector2( 0, 0 )">
- Coordinates of the frame to display from sprite sheet. This is as an alias for the [member frame] property. [member vframes] or [member hframes] must be greater than 1.
+ Coordinates of the frame to display from sprite sheet. This is as an alias for the [member frame] property. [member hframes] or [member vframes] must be greater than 1.
</member>
<member name="hframes" type="int" setter="set_hframes" getter="get_hframes" default="1">
The number of columns in the sprite sheet.
diff --git a/doc/classes/Sprite3D.xml b/doc/classes/Sprite3D.xml
index f59d5130c9..934471c445 100644
--- a/doc/classes/Sprite3D.xml
+++ b/doc/classes/Sprite3D.xml
@@ -13,10 +13,10 @@
</methods>
<members>
<member name="frame" type="int" setter="set_frame" getter="get_frame" default="0">
- Current frame to display from sprite sheet. [member vframes] or [member hframes] must be greater than 1.
+ Current frame to display from sprite sheet. [member hframes] or [member vframes] must be greater than 1.
</member>
<member name="frame_coords" type="Vector2" setter="set_frame_coords" getter="get_frame_coords" default="Vector2( 0, 0 )">
- Coordinates of the frame to display from sprite sheet. This is as an alias for the [member frame] property. [member vframes] or [member hframes] must be greater than 1.
+ Coordinates of the frame to display from sprite sheet. This is as an alias for the [member frame] property. [member hframes] or [member vframes] must be greater than 1.
</member>
<member name="hframes" type="int" setter="set_hframes" getter="get_hframes" default="1">
The number of columns in the sprite sheet.
diff --git a/doc/classes/SpriteFrames.xml b/doc/classes/SpriteFrames.xml
index 6e1e1688f4..516ae25e92 100644
--- a/doc/classes/SpriteFrames.xml
+++ b/doc/classes/SpriteFrames.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
Sprite frame library for [AnimatedSprite2D]. Contains frames and animation data for playback.
+ [b]Note:[/b] You can associate a set of normal or specular maps by creating additional [SpriteFrames] resources with a [code]_normal[/code] or [code]_specular[/code] suffix. For example, having 3 [SpriteFrames] resources [code]run[/code], [code]run_normal[/code], and [code]run_specular[/code] will make it so the [code]run[/code] animation uses normal and specular maps.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/StreamPeerSSL.xml b/doc/classes/StreamPeerSSL.xml
index 69e8f67a5e..6a06c0b3f4 100644
--- a/doc/classes/StreamPeerSSL.xml
+++ b/doc/classes/StreamPeerSSL.xml
@@ -7,7 +7,7 @@
SSL stream peer. This object can be used to connect to an SSL server or accept a single SSL client connection.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/networking/ssl_certificates.html</link>
+ <link title="SSL certificates">https://docs.godotengine.org/en/latest/tutorials/networking/ssl_certificates.html</link>
</tutorials>
<methods>
<method name="accept_stream">
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index ded64761d0..40fff25fc4 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -7,7 +7,7 @@
This is the built-in string class (and the one used by GDScript). It supports Unicode and provides all necessary means for string handling. Strings are reference-counted and use a copy-on-write approach, so passing them around is cheap in resources.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/gdscript_format_string.html</link>
+ <link title="GDScript format strings">https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/gdscript_format_string.html</link>
</tutorials>
<methods>
<method name="String">
@@ -654,6 +654,17 @@
Returns the string's amount of characters.
</description>
</method>
+ <method name="lpad">
+ <return type="String">
+ </return>
+ <argument index="0" name="min_length" type="int">
+ </argument>
+ <argument index="1" name="character" type="String" default="&quot; &quot;">
+ </argument>
+ <description>
+ Formats a string to be at least [code]min_length[/code] long by adding [code]character[/code]s to the left of the string.
+ </description>
+ </method>
<method name="lstrip">
<return type="String">
</return>
@@ -695,6 +706,15 @@
Returns the MD5 hash of the string as a string.
</description>
</method>
+ <method name="naturalnocasecmp_to">
+ <return type="int">
+ </return>
+ <argument index="0" name="to" type="String">
+ </argument>
+ <description>
+ Performs a case-insensitive natural order comparison to another string. Returns [code]-1[/code] if less than, [code]+1[/code] if greater than, or [code]0[/code] if equal.
+ </description>
+ </method>
<method name="nocasecmp_to">
<return type="int">
</return>
@@ -816,6 +836,17 @@
Returns the right side of the string from a given position.
</description>
</method>
+ <method name="rpad">
+ <return type="String">
+ </return>
+ <argument index="0" name="min_length" type="int">
+ </argument>
+ <argument index="1" name="character" type="String" default="&quot; &quot;">
+ </argument>
+ <description>
+ Formats a string to be at least [code]min_length[/code] long by adding [code]character[/code]s to the right of the string.
+ </description>
+ </method>
<method name="rsplit">
<return type="PackedStringArray">
</return>
@@ -953,7 +984,7 @@
<return type="PackedByteArray">
</return>
<description>
- Converts the String (which is a character array) to [PackedByteArray] (which is an array of bytes). The conversion is faster compared to [method to_utf8], as this method assumes that all the characters in the String are ASCII characters.
+ Converts the String (which is a character array) to ASCII/Latin-1 encoded [PackedByteArray] (which is an array of bytes). The conversion is faster compared to [method to_utf8], as this method assumes that all the characters in the String are ASCII/Latin-1 characters, unsupported characters are replaced with spaces.
</description>
</method>
<method name="to_float">
@@ -984,11 +1015,25 @@
Returns the string converted to uppercase.
</description>
</method>
+ <method name="to_utf16">
+ <return type="PackedByteArray">
+ </return>
+ <description>
+ Converts the String (which is an array of characters) to UTF-16 encoded [PackedByteArray] (which is an array of bytes).
+ </description>
+ </method>
+ <method name="to_utf32">
+ <return type="PackedByteArray">
+ </return>
+ <description>
+ Converts the String (which is an array of characters) to UTF-32 encoded [PackedByteArray] (which is an array of bytes).
+ </description>
+ </method>
<method name="to_utf8">
<return type="PackedByteArray">
</return>
<description>
- Converts the String (which is an array of characters) to [PackedByteArray] (which is an array of bytes). The conversion is a bit slower than [method to_ascii], but supports all UTF-8 characters. Therefore, you should prefer this function over [method to_ascii].
+ Converts the String (which is an array of characters) to UTF-8 encode [PackedByteArray] (which is an array of bytes). The conversion is a bit slower than [method to_ascii], but supports all UTF-8 characters. Therefore, you should prefer this function over [method to_ascii].
</description>
</method>
<method name="trim_prefix">
diff --git a/doc/classes/SubViewport.xml b/doc/classes/SubViewport.xml
index 6014762e3d..c9c7589631 100644
--- a/doc/classes/SubViewport.xml
+++ b/doc/classes/SubViewport.xml
@@ -11,6 +11,7 @@
<members>
<member name="render_target_clear_mode" type="int" setter="set_clear_mode" getter="get_clear_mode" enum="SubViewport.ClearMode" default="0">
The clear mode when the sub-viewport is used as a render target.
+ [b]Note:[/b] This property is intended for 2D usage.
</member>
<member name="render_target_update_mode" type="int" setter="set_update_mode" getter="get_update_mode" enum="SubViewport.UpdateMode" default="2">
The update mode when the sub-viewport is used as a render target.
diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index d4abac15c0..ccc99dc8e3 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -404,10 +404,10 @@
If [code]true[/code], read-only mode is enabled. Existing text cannot be modified and new text cannot be added.
</member>
<member name="scroll_horizontal" type="int" setter="set_h_scroll" getter="get_h_scroll" default="0">
- The current horizontal scroll value.
+ If there is a horizontal scrollbar this determines the current horizontal scroll value in pixels.
</member>
<member name="scroll_vertical" type="float" setter="set_v_scroll" getter="get_v_scroll" default="0.0">
- The current vertical scroll value.
+ If there is a vertical scrollbar this determines the current vertical scroll value in line numbers, starting at 0 for the top line.
</member>
<member name="selecting_enabled" type="bool" setter="set_selecting_enabled" getter="is_selecting_enabled" default="true">
If [code]true[/code], text can be selected.
diff --git a/doc/classes/Texture2D.xml b/doc/classes/Texture2D.xml
index ffe806cef7..f283efdc3d 100644
--- a/doc/classes/Texture2D.xml
+++ b/doc/classes/Texture2D.xml
@@ -96,7 +96,7 @@
<return type="Image">
</return>
<description>
- Returns an [Image] with the data from this [Texture2D]. [Image]s can be accessed and manipulated directly.
+ Returns an [Image] that is a copy of data from this [Texture2D]. [Image]s can be accessed and manipulated directly.
</description>
</method>
<method name="get_height" qualifiers="const">
diff --git a/doc/classes/Theme.xml b/doc/classes/Theme.xml
index 70a4eda867..2824159f0e 100644
--- a/doc/classes/Theme.xml
+++ b/doc/classes/Theme.xml
@@ -8,7 +8,7 @@
Theme resources can alternatively be loaded by writing them in a [code].theme[/code] file, see the documentation for more information.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/gui/gui_skinning.html</link>
+ <link title="GUI skinning">https://docs.godotengine.org/en/latest/tutorials/gui/gui_skinning.html</link>
</tutorials>
<methods>
<method name="clear">
diff --git a/doc/classes/Thread.xml b/doc/classes/Thread.xml
index 5c63d01322..46377ecf20 100644
--- a/doc/classes/Thread.xml
+++ b/doc/classes/Thread.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
A unit of execution in a process. Can run methods on [Object]s simultaneously. The use of synchronization via [Mutex] or [Semaphore] is advised if working with shared objects.
+ [b]Note:[/b] Breakpoints won't break on code if it's running in a thread. This is a current limitation of the GDScript debugger.
</description>
<tutorials>
<link title="Using multiple threads">https://docs.godotengine.org/en/latest/tutorials/threads/using_multiple_threads.html</link>
@@ -15,7 +16,7 @@
<return type="String">
</return>
<description>
- Returns the current [Thread]'s ID, uniquely identifying it among all threads.
+ Returns the current [Thread]'s ID, uniquely identifying it among all threads. If the [Thread] is not running this returns an empty string.
</description>
</method>
<method name="is_active" qualifiers="const">
diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml
index 9df2b656f4..2780545f55 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -7,7 +7,7 @@
Node for 2D tile-based maps. Tilemaps use a [TileSet] which contain a list of tiles (textures plus optional collision, navigation, and/or occluder shapes) which are used to create grid-based maps.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/2d/using_tilemaps.html</link>
+ <link title="Using Tilemaps">https://docs.godotengine.org/en/latest/tutorials/2d/using_tilemaps.html</link>
</tutorials>
<methods>
<method name="clear">
@@ -166,7 +166,7 @@
If you need these to be immediately updated, you can call [method update_dirty_quadrants].
Overriding this method also overrides it internally, allowing custom logic to be implemented when tiles are placed/removed:
[codeblock]
- func set_cell(x, y, tile, flip_x, flip_y, transpose, autotile_coord)
+ func set_cell(x, y, tile, flip_x=false, flip_y=false, transpose=false, autotile_coord=Vector2())
# Write your custom logic here.
# To call the default method:
.set_cell(x, y, tile, flip_x, flip_y, transpose, autotile_coord)
@@ -287,10 +287,10 @@
Friction value for static body collisions (see [code]collision_use_kinematic[/code]).
</member>
<member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
- The collision layer(s) for all colliders in the TileMap.
+ The collision layer(s) for all colliders in the TileMap. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The collision mask(s) for all colliders in the TileMap.
+ The collision mask(s) for all colliders in the TileMap. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="collision_use_kinematic" type="bool" setter="set_collision_use_kinematic" getter="get_collision_use_kinematic" default="false">
If [code]true[/code], TileMap collisions will be handled as a kinematic body. If [code]false[/code], collisions will be handled as static body.
diff --git a/doc/classes/TouchScreenButton.xml b/doc/classes/TouchScreenButton.xml
index c7f886b3f2..355804f2a3 100644
--- a/doc/classes/TouchScreenButton.xml
+++ b/doc/classes/TouchScreenButton.xml
@@ -1,10 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="TouchScreenButton" inherits="Node2D" version="4.0">
<brief_description>
- Button for touch screen devices.
+ Button for touch screen devices for gameplay use.
</brief_description>
<description>
- Button for touch screen devices. You can set it to be visible on all screens, or only on touch devices.
+ 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.
+ 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.
+ You can configure TouchScreenButton to be visible only on touch devices, helping you develop your game both for desktop and mobile devices.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/Transform.xml b/doc/classes/Transform.xml
index 26c190bfa9..09dfe56f8f 100644
--- a/doc/classes/Transform.xml
+++ b/doc/classes/Transform.xml
@@ -8,9 +8,9 @@
For more information, read the "Matrices and transforms" documentation article.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/math/matrices_and_transforms.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html</link>
+ <link title="Math tutorial index">https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
+ <link title="Matrices and transforms">https://docs.godotengine.org/en/latest/tutorials/math/matrices_and_transforms.html</link>
+ <link title="Using 3D transforms">https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html</link>
</tutorials>
<methods>
<method name="Transform">
diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml
index f630df7afe..5da88892fe 100644
--- a/doc/classes/Transform2D.xml
+++ b/doc/classes/Transform2D.xml
@@ -8,7 +8,7 @@
For more information, read the "Matrices and transforms" documentation article.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/math/matrices_and_transforms.html</link>
+ <link title="Matrices and transforms">https://docs.godotengine.org/en/latest/tutorials/math/matrices_and_transforms.html</link>
</tutorials>
<methods>
<method name="Transform2D">
diff --git a/doc/classes/Translation.xml b/doc/classes/Translation.xml
index 1989a63362..d286c6cf0c 100644
--- a/doc/classes/Translation.xml
+++ b/doc/classes/Translation.xml
@@ -7,8 +7,8 @@
Translations are resources that can be loaded and unloaded on demand. They map a string to another string.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/i18n/internationalizing_games.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/i18n/locales.html</link>
+ <link title="Internationalizing games">https://docs.godotengine.org/en/latest/tutorials/i18n/internationalizing_games.html</link>
+ <link title="Locales">https://docs.godotengine.org/en/latest/tutorials/i18n/locales.html</link>
</tutorials>
<methods>
<method name="add_message">
diff --git a/doc/classes/TranslationServer.xml b/doc/classes/TranslationServer.xml
index 3369663af6..664cb3e2e3 100644
--- a/doc/classes/TranslationServer.xml
+++ b/doc/classes/TranslationServer.xml
@@ -7,8 +7,8 @@
Server that manages all translations. Translations can be set to it and removed from it.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/i18n/internationalizing_games.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/i18n/locales.html</link>
+ <link title="Internationalizing games">https://docs.godotengine.org/en/latest/tutorials/i18n/internationalizing_games.html</link>
+ <link title="Locales">https://docs.godotengine.org/en/latest/tutorials/i18n/locales.html</link>
</tutorials>
<methods>
<method name="add_translation">
diff --git a/doc/classes/Variant.xml b/doc/classes/Variant.xml
index 042c8d8e67..cd76689ffe 100644
--- a/doc/classes/Variant.xml
+++ b/doc/classes/Variant.xml
@@ -50,7 +50,7 @@
Modifications to a container will modify all references to it. A [Mutex] should be created to lock it if multi-threaded access is desired.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/development/cpp/variant_class.html</link>
+ <link title="Variant class">https://docs.godotengine.org/en/latest/development/cpp/variant_class.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml
index 11716f511b..52d719b6f7 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -9,7 +9,7 @@
[b]Note:[/b] In a boolean context, a Vector2 will evaluate to [code]false[/code] if it's equal to [code]Vector2(0, 0)[/code]. Otherwise, a Vector2 will always evaluate to [code]true[/code].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
+ <link title="Math tutorial index">https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
</tutorials>
<methods>
<method name="Vector2">
diff --git a/doc/classes/Vector2i.xml b/doc/classes/Vector2i.xml
index d03db712fc..3ad926210b 100644
--- a/doc/classes/Vector2i.xml
+++ b/doc/classes/Vector2i.xml
@@ -9,7 +9,7 @@
[b]Note:[/b] In a boolean context, a Vector2i will evaluate to [code]false[/code] if it's equal to [code]Vector2i(0, 0)[/code]. Otherwise, a Vector2i will always evaluate to [code]true[/code].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
+ <link title="Math tutorial index">https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
</tutorials>
<methods>
<method name="Vector2i">
diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml
index 776dfd929e..608b976f6f 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -9,7 +9,7 @@
[b]Note:[/b] In a boolean context, a Vector3 will evaluate to [code]false[/code] if it's equal to [code]Vector3(0, 0, 0)[/code]. Otherwise, a Vector3 will always evaluate to [code]true[/code].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
+ <link title="Math tutorial index">https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
</tutorials>
<methods>
<method name="Vector3">
diff --git a/doc/classes/Vector3i.xml b/doc/classes/Vector3i.xml
index 94551e1c2f..bd7c354241 100644
--- a/doc/classes/Vector3i.xml
+++ b/doc/classes/Vector3i.xml
@@ -9,7 +9,7 @@
[b]Note:[/b] In a boolean context, a Vector3i will evaluate to [code]false[/code] if it's equal to [code]Vector3i(0, 0, 0)[/code]. Otherwise, a Vector3i will always evaluate to [code]true[/code].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
+ <link title="Math tutorial index">https://docs.godotengine.org/en/latest/tutorials/math/index.html</link>
</tutorials>
<methods>
<method name="Vector3i">
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index 3294ab4cc7..e42c4021ab 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -12,8 +12,8 @@
Finally, viewports can also behave as render targets, in which case they will not be visible unless the associated texture is used to draw.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/2d/2d_transforms.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/viewports/index.html</link>
+ <link title="Viewport and canvas transforms">https://docs.godotengine.org/en/latest/tutorials/2d/2d_transforms.html</link>
+ <link title="Viewports tutorial index">https://docs.godotengine.org/en/latest/tutorials/viewports/index.html</link>
</tutorials>
<methods>
<method name="find_world_2d" qualifiers="const">
diff --git a/doc/classes/VisualShader.xml b/doc/classes/VisualShader.xml
index 40b0f52469..12954beb43 100644
--- a/doc/classes/VisualShader.xml
+++ b/doc/classes/VisualShader.xml
@@ -193,7 +193,6 @@
</method>
</methods>
<members>
- <member name="code" type="String" setter="set_code" getter="get_code" override="true" default="&quot;shader_type spatial;void vertex() {// Output:0}void fragment() {// Output:0}void light() {// Output:0}&quot;" />
<member name="graph_offset" type="Vector2" setter="set_graph_offset" getter="get_graph_offset" default="Vector2( 0, 0 )">
The offset vector of the whole graph.
</member>
@@ -210,7 +209,10 @@
<constant name="TYPE_LIGHT" value="2" enum="Type">
A shader for light calculations.
</constant>
- <constant name="TYPE_MAX" value="3" enum="Type">
+ <constant name="TYPE_COMPUTE" value="3" enum="Type">
+ A compute shader, to use the GPU for abstract computation.
+ </constant>
+ <constant name="TYPE_MAX" value="4" enum="Type">
Represents the size of the [enum Type] enum.
</constant>
<constant name="NODE_ID_INVALID" value="-1">
diff --git a/doc/classes/VisualShaderNode.xml b/doc/classes/VisualShaderNode.xml
index 28d13a7d32..6327ab534f 100644
--- a/doc/classes/VisualShaderNode.xml
+++ b/doc/classes/VisualShaderNode.xml
@@ -6,7 +6,7 @@
<description>
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/shading/visual_shaders.html</link>
+ <link title="VisualShaders">https://docs.godotengine.org/en/latest/tutorials/shading/visual_shaders.html</link>
</tutorials>
<methods>
<method name="get_default_input_values" qualifiers="const">
diff --git a/doc/classes/VisualShaderNodeCustom.xml b/doc/classes/VisualShaderNodeCustom.xml
index 5bd8ec38ed..59b501660a 100644
--- a/doc/classes/VisualShaderNodeCustom.xml
+++ b/doc/classes/VisualShaderNodeCustom.xml
@@ -5,15 +5,15 @@
</brief_description>
<description>
By inheriting this class you can create a custom [VisualShader] script addon which will be automatically added to the Visual Shader Editor. The [VisualShaderNode]'s behavior is defined by overriding the provided virtual methods.
- In order for the node to be registered as an editor addon, you must use the [code]tool[/code] keyword and provide a [code]class_name[/code] for your custom script. For example:
+ In order for the node to be registered as an editor addon, you must use the [code]@tool[/code] annotation and provide a [code]class_name[/code] for your custom script. For example:
[codeblock]
- tool
+ @tool
extends VisualShaderNodeCustom
class_name VisualShaderNodeNoise
[/codeblock]
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/plugins/editor/visual_shader_plugins.html</link>
+ <link title="Visual Shader plugins">https://docs.godotengine.org/en/latest/tutorials/plugins/editor/visual_shader_plugins.html</link>
</tutorials>
<methods>
<method name="_get_category" qualifiers="virtual">
diff --git a/doc/classes/VisualShaderNodeInput.xml b/doc/classes/VisualShaderNodeInput.xml
index 9261d0088d..8e819b011c 100644
--- a/doc/classes/VisualShaderNodeInput.xml
+++ b/doc/classes/VisualShaderNodeInput.xml
@@ -7,7 +7,7 @@
Gives access to input variables (built-ins) available for the shader. See the shading reference for the list of available built-ins for each shader type (check [code]Tutorials[/code] section for link).
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/stable/tutorials/shading/shading_reference/index.html</link>
+ <link title="Shading reference index">https://docs.godotengine.org/en/stable/tutorials/shading/shading_reference/index.html</link>
</tutorials>
<methods>
<method name="get_input_real_name" qualifiers="const">
diff --git a/doc/classes/World2D.xml b/doc/classes/World2D.xml
index e66f21a0e7..b0bfd7f418 100644
--- a/doc/classes/World2D.xml
+++ b/doc/classes/World2D.xml
@@ -7,7 +7,7 @@
Class that has everything pertaining to a 2D world. A physics space, a visual scenario and a sound space. 2D nodes register their resources into the current 2D world.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
+ <link title="Ray-casting">https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/World3D.xml b/doc/classes/World3D.xml
index 6d3b94794e..d804485d4e 100644
--- a/doc/classes/World3D.xml
+++ b/doc/classes/World3D.xml
@@ -7,7 +7,7 @@
Class that has everything pertaining to a world. A physics space, a visual scenario and a sound space. Node3D nodes register their resources into the current world.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
+ <link title="Ray-casting">https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/WorldEnvironment.xml b/doc/classes/WorldEnvironment.xml
index 92b75621c2..f9f0241365 100644
--- a/doc/classes/WorldEnvironment.xml
+++ b/doc/classes/WorldEnvironment.xml
@@ -9,7 +9,7 @@
The [WorldEnvironment] allows the user to specify default lighting parameters (e.g. ambient lighting), various post-processing effects (e.g. SSAO, DOF, Tonemapping), and how to draw the background (e.g. solid color, skybox). Usually, these are added in order to improve the realism/color balance of the scene.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/environment_and_post_processing.html</link>
+ <link title="Environment and post-processing">https://docs.godotengine.org/en/latest/tutorials/3d/environment_and_post_processing.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/XRCamera3D.xml b/doc/classes/XRCamera3D.xml
index 4d86e24daa..b2682f7a90 100644
--- a/doc/classes/XRCamera3D.xml
+++ b/doc/classes/XRCamera3D.xml
@@ -8,7 +8,7 @@
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>
- <link>https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
+ <link title="VR tutorial index">https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/XRController3D.xml b/doc/classes/XRController3D.xml
index 8e80eb9a32..c0f64d9e27 100644
--- a/doc/classes/XRController3D.xml
+++ b/doc/classes/XRController3D.xml
@@ -9,7 +9,7 @@
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.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
+ <link title="VR tutorial index">https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
</tutorials>
<methods>
<method name="get_controller_name" qualifiers="const">
diff --git a/doc/classes/XRInterface.xml b/doc/classes/XRInterface.xml
index 1985010223..034cb51be3 100644
--- a/doc/classes/XRInterface.xml
+++ b/doc/classes/XRInterface.xml
@@ -8,7 +8,7 @@
Interfaces should be written in such a way that simply enabling them will give us a working setup. You can query the available interfaces through [XRServer].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
+ <link title="VR tutorial index">https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
</tutorials>
<methods>
<method name="get_camera_feed_id">
diff --git a/doc/classes/XROrigin3D.xml b/doc/classes/XROrigin3D.xml
index 57cf673d30..3e075e99b9 100644
--- a/doc/classes/XROrigin3D.xml
+++ b/doc/classes/XROrigin3D.xml
@@ -10,7 +10,7 @@
For example, if your character is driving a car, the XROrigin3D node should be a child node of this car. Or, if you're implementing a teleport system to move your character, you should change the position of this node.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
+ <link title="VR tutorial index">https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
</tutorials>
<methods>
</methods>
diff --git a/doc/classes/XRPositionalTracker.xml b/doc/classes/XRPositionalTracker.xml
index 2f7cc21703..0b57c9478f 100644
--- a/doc/classes/XRPositionalTracker.xml
+++ b/doc/classes/XRPositionalTracker.xml
@@ -9,7 +9,7 @@
The [XRController3D] and [XRAnchor3D] both consume objects of this type and should be used in your project. The positional trackers are just under-the-hood objects that make this all work. These are mostly exposed so that GDNative-based interfaces can interact with them.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
+ <link title="VR tutorial index">https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
</tutorials>
<methods>
<method name="get_hand" qualifiers="const">
diff --git a/doc/classes/XRServer.xml b/doc/classes/XRServer.xml
index 5e6002aee3..75a05bef17 100644
--- a/doc/classes/XRServer.xml
+++ b/doc/classes/XRServer.xml
@@ -7,7 +7,7 @@
The AR/VR server is the heart of our Advanced and Virtual Reality solution and handles all the processing.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
+ <link title="VR tutorial index">https://docs.godotengine.org/en/latest/tutorials/vr/index.html</link>
</tutorials>
<methods>
<method name="center_on_hmd">
diff --git a/drivers/alsa/audio_driver_alsa.h b/drivers/alsa/audio_driver_alsa.h
index 7aec0c4071..d1220d126e 100644
--- a/drivers/alsa/audio_driver_alsa.h
+++ b/drivers/alsa/audio_driver_alsa.h
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef ALSA_ENABLED
-
#ifndef AUDIO_DRIVER_ALSA_H
#define AUDIO_DRIVER_ALSA_H
+#ifdef ALSA_ENABLED
+
#include "core/os/mutex.h"
#include "core/os/thread.h"
#include "servers/audio_server.h"
@@ -88,6 +88,6 @@ public:
~AudioDriverALSA() {}
};
-#endif // AUDIO_DRIVER_ALSA_H
-
#endif // ALSA_ENABLED
+
+#endif // AUDIO_DRIVER_ALSA_H
diff --git a/drivers/alsamidi/midi_driver_alsamidi.h b/drivers/alsamidi/midi_driver_alsamidi.h
index e8ed6df5b0..6aabe8e3fd 100644
--- a/drivers/alsamidi/midi_driver_alsamidi.h
+++ b/drivers/alsamidi/midi_driver_alsamidi.h
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef ALSAMIDI_ENABLED
-
#ifndef MIDI_DRIVER_ALSAMIDI_H
#define MIDI_DRIVER_ALSAMIDI_H
+#ifdef ALSAMIDI_ENABLED
+
#include "core/os/midi_driver.h"
#include "core/os/mutex.h"
#include "core/os/thread.h"
@@ -64,5 +64,6 @@ public:
virtual ~MIDIDriverALSAMidi();
};
-#endif // MIDI_DRIVER_ALSAMIDI_H
#endif // ALSAMIDI_ENABLED
+
+#endif // MIDI_DRIVER_ALSAMIDI_H
diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h
index 0d2d6b38a7..5947d7a5e5 100644
--- a/drivers/dummy/rasterizer_dummy.h
+++ b/drivers/dummy/rasterizer_dummy.h
@@ -88,6 +88,7 @@ public:
void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) {}
virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) {}
+ virtual void environment_glow_set_use_high_quality(bool p_enable) {}
void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) {}
void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) {}
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h
index 2f2ad0fc38..35ccae94b8 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.h
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.h
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef PULSEAUDIO_ENABLED
-
#ifndef AUDIO_DRIVER_PULSEAUDIO_H
#define AUDIO_DRIVER_PULSEAUDIO_H
+#ifdef PULSEAUDIO_ENABLED
+
#include "core/os/mutex.h"
#include "core/os/thread.h"
#include "servers/audio_server.h"
@@ -124,6 +124,6 @@ public:
~AudioDriverPulseAudio() {}
};
-#endif // AUDIO_DRIVER_PULSEAUDIO_H
-
#endif // PULSEAUDIO_ENABLED
+
+#endif // AUDIO_DRIVER_PULSEAUDIO_H
diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp
index 06bad9f385..51c657007c 100644
--- a/drivers/unix/file_access_unix.cpp
+++ b/drivers/unix/file_access_unix.cpp
@@ -78,7 +78,7 @@ Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) {
path_src = p_path;
path = fix_path(p_path);
- //printf("opening %ls, %i\n", path.c_str(), Memory::get_static_mem_usage());
+ //printf("opening %s, %i\n", path.utf8().get_data(), Memory::get_static_mem_usage());
ERR_FAIL_COND_V_MSG(f, ERR_ALREADY_IN_USE, "File is already in use.");
const char *mode_string;
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index 3c212cadb8..6b98a344dc 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -171,52 +171,53 @@ double OS_Unix::get_unix_time() const {
OS::Date OS_Unix::get_date(bool utc) const {
time_t t = time(nullptr);
- struct tm *lt;
+ struct tm lt;
if (utc) {
- lt = gmtime(&t);
+ gmtime_r(&t, &lt);
} else {
- lt = localtime(&t);
+ localtime_r(&t, &lt);
}
Date ret;
- ret.year = 1900 + lt->tm_year;
+ ret.year = 1900 + lt.tm_year;
// Index starting at 1 to match OS_Unix::get_date
// and Windows SYSTEMTIME and tm_mon follows the typical structure
// of 0-11, noted here: http://www.cplusplus.com/reference/ctime/tm/
- ret.month = (Month)(lt->tm_mon + 1);
- ret.day = lt->tm_mday;
- ret.weekday = (Weekday)lt->tm_wday;
- ret.dst = lt->tm_isdst;
+ ret.month = (Month)(lt.tm_mon + 1);
+ ret.day = lt.tm_mday;
+ ret.weekday = (Weekday)lt.tm_wday;
+ ret.dst = lt.tm_isdst;
return ret;
}
OS::Time OS_Unix::get_time(bool utc) const {
time_t t = time(nullptr);
- struct tm *lt;
+ struct tm lt;
if (utc) {
- lt = gmtime(&t);
+ gmtime_r(&t, &lt);
} else {
- lt = localtime(&t);
+ localtime_r(&t, &lt);
}
Time ret;
- ret.hour = lt->tm_hour;
- ret.min = lt->tm_min;
- ret.sec = lt->tm_sec;
+ ret.hour = lt.tm_hour;
+ ret.min = lt.tm_min;
+ ret.sec = lt.tm_sec;
get_time_zone_info();
return ret;
}
OS::TimeZoneInfo OS_Unix::get_time_zone_info() const {
time_t t = time(nullptr);
- struct tm *lt = localtime(&t);
+ struct tm lt;
+ localtime_r(&t, &lt);
char name[16];
- strftime(name, 16, "%Z", lt);
+ strftime(name, 16, "%Z", &lt);
name[15] = 0;
TimeZoneInfo ret;
ret.name = name;
char bias_buf[16];
- strftime(bias_buf, 16, "%z", lt);
+ strftime(bias_buf, 16, "%z", &lt);
int bias;
bias_buf[15] = 0;
sscanf(bias_buf, "%d", &bias);
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index fb890491a4..9fe3f7e6c0 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -3650,7 +3650,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
//print_line("DEBUG: SAMPLER: texel buffer");
} else {
if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' is of unsupported buffer type.";
+ *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' is of unsupported buffer type.";
}
return false;
}
@@ -3673,7 +3673,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
} else {
//print_line("DEBUG: sampler unknown");
if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' is of unsupported sampler type.";
+ *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' is of unsupported sampler type.";
}
return false;
}
@@ -3698,7 +3698,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
if (reflection.getType()->getQualifier().layoutPushConstant) {
uint32_t len = reflection.size;
if (push_constant.push_constant_size != 0 && push_constant.push_constant_size != len) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' push constants for different stages should all be the same size.";
+ *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' push constants for different stages should all be the same size.";
return false;
}
push_constant.push_constant_size = len;
@@ -3714,7 +3714,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
//print_line("DEBUG: Storage buffer");
} else {
if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' is of unsupported block type: (" + itos(reflection.getType()->getQualifier().storage) + ").";
+ *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' is of unsupported block type: (" + itos(reflection.getType()->getQualifier().storage) + ").";
}
return false;
}
@@ -3743,7 +3743,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
}
if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' unsupported uniform type.";
+ *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' unsupported uniform type.";
}
return false;
}
@@ -3751,7 +3751,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
if (!reflection.getType()->getQualifier().hasBinding()) {
if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' lacks a binding number.";
+ *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' lacks a binding number.";
}
return false;
}
@@ -3760,14 +3760,14 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
if (set >= MAX_UNIFORM_SETS) {
if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' uses a set (" + itos(set) + ") index larger than what is supported (" + itos(MAX_UNIFORM_SETS) + ").";
+ *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' uses a set (" + itos(set) + ") index larger than what is supported (" + itos(MAX_UNIFORM_SETS) + ").";
}
return false;
}
if (set >= limits.maxBoundDescriptorSets) {
if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' uses a set (" + itos(set) + ") index larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ").";
+ *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' uses a set (" + itos(set) + ") index larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ").";
}
return false;
}
@@ -3781,7 +3781,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
//already exists, verify that it's the same type
if (bindings[set][i].descriptorType != layout_binding.descriptorType) {
if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(binding) + " with different uniform type.";
+ *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(binding) + " with different uniform type.";
}
return false;
}
@@ -3789,7 +3789,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
//also, verify that it's the same size
if (bindings[set][i].descriptorCount != layout_binding.descriptorCount || uniform_infos[set][i].length != info.length) {
if (r_error) {
- *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name.c_str() + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(binding) + " with different uniform size.";
+ *r_error = "On shader stage '" + String(shader_stage_names[p_stage]) + "', uniform '" + reflection.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(binding) + " with different uniform size.";
}
return false;
}
diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp
index b8153907a9..03e4e30797 100644
--- a/drivers/windows/dir_access_windows.cpp
+++ b/drivers/windows/dir_access_windows.cpp
@@ -65,7 +65,7 @@ Error DirAccessWindows::list_dir_begin() {
_cishidden = false;
list_dir_end();
- p->h = FindFirstFileExW((current_dir + "\\*").c_str(), FindExInfoStandard, &p->fu, FindExSearchNameMatch, nullptr, 0);
+ p->h = FindFirstFileExW((LPCWSTR)(String(current_dir + "\\*").utf16().get_data()), FindExInfoStandard, &p->fu, FindExSearchNameMatch, nullptr, 0);
if (p->h == INVALID_HANDLE_VALUE) {
return ERR_CANT_OPEN;
@@ -75,13 +75,14 @@ Error DirAccessWindows::list_dir_begin() {
}
String DirAccessWindows::get_next() {
- if (p->h == INVALID_HANDLE_VALUE)
+ if (p->h == INVALID_HANDLE_VALUE) {
return "";
+ }
_cisdir = (p->fu.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
_cishidden = (p->fu.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN);
- String name = p->fu.cFileName;
+ String name = String::utf16((const char16_t *)(p->fu.cFileName));
if (FindNextFileW(p->h, &p->fu) == 0) {
FindClose(p->h);
@@ -111,8 +112,9 @@ int DirAccessWindows::get_drive_count() {
}
String DirAccessWindows::get_drive(int p_drive) {
- if (p_drive < 0 || p_drive >= drive_count)
+ if (p_drive < 0 || p_drive >= drive_count) {
return "";
+ }
return String::chr(drives[p_drive]) + ":";
}
@@ -122,18 +124,17 @@ Error DirAccessWindows::change_dir(String p_dir) {
p_dir = fix_path(p_dir);
- wchar_t real_current_dir_name[2048];
+ WCHAR real_current_dir_name[2048];
GetCurrentDirectoryW(2048, real_current_dir_name);
- String prev_dir = real_current_dir_name;
+ String prev_dir = String::utf16((const char16_t *)real_current_dir_name);
- SetCurrentDirectoryW(current_dir.c_str());
- bool worked = (SetCurrentDirectoryW(p_dir.c_str()) != 0);
+ SetCurrentDirectoryW((LPCWSTR)(current_dir.utf16().get_data()));
+ bool worked = (SetCurrentDirectoryW((LPCWSTR)(p_dir.utf16().get_data())) != 0);
String base = _get_root_path();
if (base != "") {
GetCurrentDirectoryW(2048, real_current_dir_name);
- String new_dir;
- new_dir = String(real_current_dir_name).replace("\\", "/");
+ String new_dir = String::utf16((const char16_t *)real_current_dir_name).replace("\\", "/");
if (!new_dir.begins_with(base)) {
worked = false;
}
@@ -141,13 +142,11 @@ Error DirAccessWindows::change_dir(String p_dir) {
if (worked) {
GetCurrentDirectoryW(2048, real_current_dir_name);
- current_dir = real_current_dir_name; // TODO, utf8 parser
+ current_dir = String::utf16((const char16_t *)real_current_dir_name);
current_dir = current_dir.replace("\\", "/");
+ }
- } //else {
-
- SetCurrentDirectoryW(prev_dir.c_str());
- //}
+ SetCurrentDirectoryW((LPCWSTR)(prev_dir.utf16().get_data()));
return worked ? OK : ERR_INVALID_PARAMETER;
}
@@ -156,8 +155,9 @@ Error DirAccessWindows::make_dir(String p_dir) {
GLOBAL_LOCK_FUNCTION
p_dir = fix_path(p_dir);
- if (p_dir.is_rel_path())
+ if (p_dir.is_rel_path()) {
p_dir = current_dir.plus_file(p_dir);
+ }
p_dir = p_dir.replace("/", "\\");
@@ -167,16 +167,16 @@ Error DirAccessWindows::make_dir(String p_dir) {
p_dir = "\\\\?\\" + p_dir; //done according to
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363855(v=vs.85).aspx
- success = CreateDirectoryW(p_dir.c_str(), nullptr);
+ success = CreateDirectoryW((LPCWSTR)(p_dir.utf16().get_data()), nullptr);
err = GetLastError();
if (success) {
return OK;
- };
+ }
if (err == ERROR_ALREADY_EXISTS || err == ERROR_ACCESS_DENIED) {
return ERR_ALREADY_EXISTS;
- };
+ }
return ERR_CANT_CREATE;
}
@@ -185,12 +185,11 @@ String DirAccessWindows::get_current_dir(bool p_include_drive) {
String base = _get_root_path();
if (base != "") {
String bd = current_dir.replace("\\", "/").replace_first(base, "");
- if (bd.begins_with("/"))
+ if (bd.begins_with("/")) {
return _get_root_string() + bd.substr(1, bd.length());
- else
+ } else {
return _get_root_string() + bd;
-
- } else {
+ }
}
if (p_include_drive) {
@@ -209,20 +208,18 @@ String DirAccessWindows::get_current_dir(bool p_include_drive) {
bool DirAccessWindows::file_exists(String p_file) {
GLOBAL_LOCK_FUNCTION
- if (!p_file.is_abs_path())
+ if (!p_file.is_abs_path()) {
p_file = get_current_dir().plus_file(p_file);
+ }
p_file = fix_path(p_file);
- //p_file.replace("/","\\");
-
- //WIN32_FILE_ATTRIBUTE_DATA fileInfo;
-
DWORD fileAttr;
- fileAttr = GetFileAttributesW(p_file.c_str());
- if (INVALID_FILE_ATTRIBUTES == fileAttr)
+ fileAttr = GetFileAttributesW((LPCWSTR)(p_file.utf16().get_data()));
+ if (INVALID_FILE_ATTRIBUTES == fileAttr) {
return false;
+ }
return !(fileAttr & FILE_ATTRIBUTE_DIRECTORY);
}
@@ -230,31 +227,30 @@ bool DirAccessWindows::file_exists(String p_file) {
bool DirAccessWindows::dir_exists(String p_dir) {
GLOBAL_LOCK_FUNCTION
- if (p_dir.is_rel_path())
+ if (p_dir.is_rel_path()) {
p_dir = get_current_dir().plus_file(p_dir);
+ }
p_dir = fix_path(p_dir);
- //p_dir.replace("/","\\");
-
- //WIN32_FILE_ATTRIBUTE_DATA fileInfo;
-
DWORD fileAttr;
-
- fileAttr = GetFileAttributesW(p_dir.c_str());
- if (INVALID_FILE_ATTRIBUTES == fileAttr)
+ fileAttr = GetFileAttributesW((LPCWSTR)(p_dir.utf16().get_data()));
+ if (INVALID_FILE_ATTRIBUTES == fileAttr) {
return false;
+ }
return (fileAttr & FILE_ATTRIBUTE_DIRECTORY);
}
Error DirAccessWindows::rename(String p_path, String p_new_path) {
- if (p_path.is_rel_path())
+ if (p_path.is_rel_path()) {
p_path = get_current_dir().plus_file(p_path);
+ }
p_path = fix_path(p_path);
- if (p_new_path.is_rel_path())
+ if (p_new_path.is_rel_path()) {
p_new_path = get_current_dir().plus_file(p_new_path);
+ }
p_new_path = fix_path(p_new_path);
@@ -262,16 +258,16 @@ Error DirAccessWindows::rename(String p_path, String p_new_path) {
if (p_path.to_lower() == p_new_path.to_lower()) {
WCHAR tmpfile[MAX_PATH];
- if (!GetTempFileNameW(fix_path(get_current_dir()).c_str(), nullptr, 0, tmpfile)) {
+ if (!GetTempFileNameW((LPCWSTR)(fix_path(get_current_dir()).utf16().get_data()), nullptr, 0, tmpfile)) {
return FAILED;
}
- if (!::ReplaceFileW(tmpfile, p_path.c_str(), nullptr, 0, nullptr, nullptr)) {
+ if (!::ReplaceFileW(tmpfile, (LPCWSTR)(p_path.utf16().get_data()), nullptr, 0, nullptr, nullptr)) {
DeleteFileW(tmpfile);
return FAILED;
}
- return ::_wrename(tmpfile, p_new_path.c_str()) == 0 ? OK : FAILED;
+ return ::_wrename(tmpfile, (LPCWSTR)(p_new_path.utf16().get_data())) == 0 ? OK : FAILED;
} else {
if (file_exists(p_new_path)) {
@@ -280,60 +276,60 @@ Error DirAccessWindows::rename(String p_path, String p_new_path) {
}
}
- return ::_wrename(p_path.c_str(), p_new_path.c_str()) == 0 ? OK : FAILED;
+ return ::_wrename((LPCWSTR)(p_path.utf16().get_data()), (LPCWSTR)(p_new_path.utf16().get_data())) == 0 ? OK : FAILED;
}
}
Error DirAccessWindows::remove(String p_path) {
- if (p_path.is_rel_path())
+ if (p_path.is_rel_path()) {
p_path = get_current_dir().plus_file(p_path);
+ }
p_path = fix_path(p_path);
DWORD fileAttr;
- fileAttr = GetFileAttributesW(p_path.c_str());
- if (INVALID_FILE_ATTRIBUTES == fileAttr)
+ fileAttr = GetFileAttributesW((LPCWSTR)(p_path.utf16().get_data()));
+ if (INVALID_FILE_ATTRIBUTES == fileAttr) {
return FAILED;
- if ((fileAttr & FILE_ATTRIBUTE_DIRECTORY))
- return ::_wrmdir(p_path.c_str()) == 0 ? OK : FAILED;
- else
- return ::_wunlink(p_path.c_str()) == 0 ? OK : FAILED;
+ }
+ if ((fileAttr & FILE_ATTRIBUTE_DIRECTORY)) {
+ return ::_wrmdir((LPCWSTR)(p_path.utf16().get_data())) == 0 ? OK : FAILED;
+ } else {
+ return ::_wunlink((LPCWSTR)(p_path.utf16().get_data())) == 0 ? OK : FAILED;
+ }
}
/*
FileType DirAccessWindows::get_file_type(const String& p_file) const {
+ WCHAR real_current_dir_name[2048];
+ GetCurrentDirectoryW(2048, real_current_dir_name);
+ String prev_dir = Strong::utf16((const char16_t *)real_current_dir_name);
-
- wchar_t real_current_dir_name[2048];
- GetCurrentDirectoryW(2048,real_current_dir_name);
- String prev_dir=real_current_dir_name;
-
- bool worked SetCurrentDirectoryW(current_dir.c_str());
+ bool worked = SetCurrentDirectoryW((LPCWSTR)(current_dir.utf16().get_data()));
DWORD attr;
if (worked) {
-
- WIN32_FILE_ATTRIBUTE_DATA fileInfo;
- attr = GetFileAttributesExW(p_file.c_str(), GetFileExInfoStandard, &fileInfo);
-
+ WIN32_FILE_ATTRIBUTE_DATA fileInfo;
+ attr = GetFileAttributesExW((LPCWSTR)(p_file.utf16().get_data()), GetFileExInfoStandard, &fileInfo);
}
- SetCurrentDirectoryW(prev_dir.c_str());
+ SetCurrentDirectoryW((LPCWSTR)(prev_dir.utf16().get_data()));
- if (!worked)
+ if (!worked) {
return FILE_TYPE_NONE;
+ }
-
- return (attr&FILE_ATTRIBUTE_DIRECTORY)?FILE_TYPE_
+ return (attr & FILE_ATTRIBUTE_DIRECTORY) ? FILE_TYPE_
}
*/
size_t DirAccessWindows::get_space_left() {
uint64_t bytes = 0;
- if (!GetDiskFreeSpaceEx(nullptr, (PULARGE_INTEGER)&bytes, nullptr, nullptr))
+ if (!GetDiskFreeSpaceEx(nullptr, (PULARGE_INTEGER)&bytes, nullptr, nullptr)) {
return 0;
+ }
//this is either 0 or a value in bytes.
return (size_t)bytes;
@@ -352,7 +348,7 @@ String DirAccessWindows::get_filesystem_type() const {
DWORD dwMaxFileNameLength = 0;
DWORD dwFileSystemFlags = 0;
- if (::GetVolumeInformationW(unit.c_str(),
+ if (::GetVolumeInformationW((LPCWSTR)(unit.utf16().get_data()),
szVolumeName,
sizeof(szVolumeName),
&dwSerialNumber,
@@ -360,7 +356,7 @@ String DirAccessWindows::get_filesystem_type() const {
&dwFileSystemFlags,
szFileSystemName,
sizeof(szFileSystemName)) == TRUE) {
- return String(szFileSystemName);
+ return String::utf16((const char16_t *)szFileSystemName);
}
ERR_FAIL_V("");
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index 50366d0b2d..dd86061ea7 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -59,29 +59,32 @@ void FileAccessWindows::check_errors() const {
Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) {
path_src = p_path;
path = fix_path(p_path);
- if (f)
+ if (f) {
close();
+ }
- const wchar_t *mode_string;
+ const WCHAR *mode_string;
- if (p_mode_flags == READ)
+ if (p_mode_flags == READ) {
mode_string = L"rb";
- else if (p_mode_flags == WRITE)
+ } else if (p_mode_flags == WRITE) {
mode_string = L"wb";
- else if (p_mode_flags == READ_WRITE)
+ } else if (p_mode_flags == READ_WRITE) {
mode_string = L"rb+";
- else if (p_mode_flags == WRITE_READ)
+ } else if (p_mode_flags == WRITE_READ) {
mode_string = L"wb+";
- else
+ } else {
return ERR_INVALID_PARAMETER;
+ }
/* pretty much every implementation that uses fopen as primary
backend supports utf8 encoding */
struct _stat st;
- if (_wstat(path.c_str(), &st) == 0) {
- if (!S_ISREG(st.st_mode))
+ if (_wstat((LPCWSTR)(path.utf16().get_data()), &st) == 0) {
+ if (!S_ISREG(st.st_mode)) {
return ERR_FILE_CANT_OPEN;
+ }
};
#ifdef TOOLS_ENABLED
@@ -91,9 +94,9 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) {
// platforms).
if (p_mode_flags == READ) {
WIN32_FIND_DATAW d;
- HANDLE f = FindFirstFileW(path.c_str(), &d);
+ HANDLE f = FindFirstFileW((LPCWSTR)(path.utf16().get_data()), &d);
if (f != INVALID_HANDLE_VALUE) {
- String fname = d.cFileName;
+ String fname = String::utf16((const char16_t *)(d.cFileName));
if (fname != String()) {
String base_file = path.get_file();
if (base_file != fname && base_file.findn(fname) == 0) {
@@ -110,7 +113,7 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) {
path = path + ".tmp";
}
- errno_t errcode = _wfopen_s(&f, path.c_str(), mode_string);
+ errno_t errcode = _wfopen_s(&f, (LPCWSTR)(path.utf16().get_data()), mode_string);
if (f == nullptr) {
switch (errcode) {
@@ -130,8 +133,9 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) {
}
void FileAccessWindows::close() {
- if (!f)
+ if (!f) {
return;
+ }
fclose(f);
f = nullptr;
@@ -148,16 +152,16 @@ void FileAccessWindows::close() {
// UWP has no PathFileExists, so we check attributes instead
DWORD fileAttr;
- fileAttr = GetFileAttributesW(save_path.c_str());
+ fileAttr = GetFileAttributesW((LPCWSTR)(save_path.utf16().get_data()));
if (INVALID_FILE_ATTRIBUTES == fileAttr) {
#else
- if (!PathFileExistsW(save_path.c_str())) {
+ if (!PathFileExistsW((LPCWSTR)(save_path.utf16().get_data()))) {
#endif
//creating new file
- rename_error = _wrename((save_path + ".tmp").c_str(), save_path.c_str()) != 0;
+ rename_error = _wrename((LPCWSTR)((save_path + ".tmp").utf16().get_data()), (LPCWSTR)(save_path.utf16().get_data())) != 0;
} else {
//atomic replace for existing file
- rename_error = !ReplaceFileW(save_path.c_str(), (save_path + ".tmp").c_str(), nullptr, 2 | 4, nullptr, nullptr);
+ rename_error = !ReplaceFileW((LPCWSTR)(save_path.utf16().get_data()), (LPCWSTR)((save_path + ".tmp").utf16().get_data()), nullptr, 2 | 4, nullptr, nullptr);
}
if (rename_error) {
attempts--;
@@ -192,15 +196,17 @@ bool FileAccessWindows::is_open() const {
void FileAccessWindows::seek(size_t p_position) {
ERR_FAIL_COND(!f);
last_error = OK;
- if (fseek(f, p_position, SEEK_SET))
+ if (fseek(f, p_position, SEEK_SET)) {
check_errors();
+ }
prev_op = 0;
}
void FileAccessWindows::seek_end(int64_t p_position) {
ERR_FAIL_COND(!f);
- if (fseek(f, p_position, SEEK_END))
+ if (fseek(f, p_position, SEEK_END)) {
check_errors();
+ }
prev_op = 0;
}
@@ -209,7 +215,7 @@ size_t FileAccessWindows::get_position() const {
aux_position = ftell(f);
if (!aux_position) {
check_errors();
- };
+ }
return aux_position;
}
@@ -241,7 +247,7 @@ uint8_t FileAccessWindows::get_8() const {
if (fread(&b, 1, 1, f) == 0) {
check_errors();
b = '\0';
- };
+ }
return b;
}
@@ -266,8 +272,9 @@ Error FileAccessWindows::get_error() const {
void FileAccessWindows::flush() {
ERR_FAIL_COND(!f);
fflush(f);
- if (prev_op == WRITE)
+ if (prev_op == WRITE) {
prev_op = 0;
+ }
}
void FileAccessWindows::store_8(uint8_t p_dest) {
@@ -298,9 +305,9 @@ void FileAccessWindows::store_buffer(const uint8_t *p_src, int p_length) {
bool FileAccessWindows::file_exists(const String &p_name) {
FILE *g;
- //printf("opening file %s\n", p_fname.c_str());
+ //printf("opening file %s\n", p_fname.utf8().get_data());
String filename = fix_path(p_name);
- _wfopen_s(&g, filename.c_str(), L"rb");
+ _wfopen_s(&g, (LPCWSTR)(filename.utf16().get_data()), L"rb");
if (g == nullptr) {
return false;
} else {
@@ -315,7 +322,7 @@ uint64_t FileAccessWindows::_get_modified_time(const String &p_file) {
file = file.substr(0, file.length() - 1);
struct _stat st;
- int rv = _wstat(file.c_str(), &st);
+ int rv = _wstat((LPCWSTR)(file.utf16().get_data()), &st);
if (rv == 0) {
return st.st_mtime;
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index d3dff3f375..20d29d47f4 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -714,7 +714,7 @@ void ConnectionsDock::_open_connection_dialog(TreeItem &item) {
const String &signalname = signal;
String midname = selectedNode->get_name();
for (int i = 0; i < midname.length(); i++) { //TODO: Regex filter may be cleaner.
- CharType c = midname[i];
+ char32_t c = midname[i];
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')) {
if (c == ' ') {
// Replace spaces with underlines.
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index a9c18138d8..b461ac4f35 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -34,6 +34,7 @@
#include "editor/debugger/script_editor_debugger.h"
#include "editor/editor_log.h"
#include "editor/editor_node.h"
+#include "editor/plugins/editor_debugger_plugin.h"
#include "editor/plugins/script_editor_plugin.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/tab_container.h"
@@ -114,6 +115,12 @@ ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() {
tabs->add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox("DebuggerPanel", "EditorStyles"));
}
+ if (!debugger_plugins.empty()) {
+ for (Set<Ref<Script>>::Element *i = debugger_plugins.front(); i; i = i->next()) {
+ node->add_debugger_plugin(i->get());
+ }
+ }
+
return node;
}
@@ -618,3 +625,23 @@ void EditorDebuggerNode::live_debug_reparent_node(const NodePath &p_at, const No
dbg->live_debug_reparent_node(p_at, p_new_place, p_new_name, p_at_pos);
});
}
+
+void EditorDebuggerNode::add_debugger_plugin(const Ref<Script> &p_script) {
+ ERR_FAIL_COND_MSG(debugger_plugins.has(p_script), "Debugger plugin already exists.");
+ ERR_FAIL_COND_MSG(p_script.is_null(), "Debugger plugin script is null");
+ ERR_FAIL_COND_MSG(String(p_script->get_instance_base_type()) == "", "Debugger plugin script has error.");
+ ERR_FAIL_COND_MSG(String(p_script->get_instance_base_type()) != "EditorDebuggerPlugin", "Base type of debugger plugin is not 'EditorDebuggerPlugin'.");
+ ERR_FAIL_COND_MSG(!p_script->is_tool(), "Debugger plugin script is not in tool mode.");
+ debugger_plugins.insert(p_script);
+ for (int i = 0; get_debugger(i); i++) {
+ get_debugger(i)->add_debugger_plugin(p_script);
+ }
+}
+
+void EditorDebuggerNode::remove_debugger_plugin(const Ref<Script> &p_script) {
+ ERR_FAIL_COND_MSG(!debugger_plugins.has(p_script), "Debugger plugin doesn't exists.");
+ debugger_plugins.erase(p_script);
+ for (int i = 0; get_debugger(i); i++) {
+ get_debugger(i)->remove_debugger_plugin(p_script);
+ }
+}
diff --git a/editor/debugger/editor_debugger_node.h b/editor/debugger/editor_debugger_node.h
index ff9601c026..8d70a7f961 100644
--- a/editor/debugger/editor_debugger_node.h
+++ b/editor/debugger/editor_debugger_node.h
@@ -103,6 +103,8 @@ private:
CameraOverride camera_override = OVERRIDE_NONE;
Map<Breakpoint, bool> breakpoints;
+ Set<Ref<Script>> debugger_plugins;
+
ScriptEditorDebugger *_add_debugger();
EditorDebuggerRemoteObject *get_inspected_remote_object();
@@ -186,5 +188,8 @@ public:
Error start(const String &p_protocol = "tcp://");
void stop();
+
+ void add_debugger_plugin(const Ref<Script> &p_script);
+ void remove_debugger_plugin(const Ref<Script> &p_script);
};
#endif // EDITOR_DEBUGGER_NODE_H
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index 49bf068be7..1fca95b6da 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -44,6 +44,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
+#include "editor/plugins/editor_debugger_plugin.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "editor/property_editor.h"
#include "main/performance.h"
@@ -701,7 +702,28 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
performance_profiler->update_monitors(monitors);
} else {
- WARN_PRINT("unknown message " + p_msg);
+ int colon_index = p_msg.find_char(':');
+ ERR_FAIL_COND_MSG(colon_index < 1, "Invalid message received");
+
+ bool parsed = false;
+ const String cap = p_msg.substr(0, colon_index);
+ Map<StringName, Callable>::Element *element = captures.find(cap);
+ if (element) {
+ Callable &c = element->value();
+ ERR_FAIL_COND_MSG(c.is_null(), "Invalid callable registered: " + cap);
+ Variant cmd = p_msg.substr(colon_index + 1), data = p_data;
+ const Variant *args[2] = { &cmd, &data };
+ Variant retval;
+ Callable::CallError err;
+ c.call(args, 2, retval, err);
+ ERR_FAIL_COND_MSG(err.error != Callable::CallError::CALL_OK, "Error calling 'capture' to callable: " + Variant::get_callable_error_text(c, args, 2, err));
+ ERR_FAIL_COND_MSG(retval.get_type() != Variant::BOOL, "Error calling 'capture' to callable: " + String(c) + ". Return type is not bool.");
+ parsed = retval;
+ }
+
+ if (!parsed) {
+ WARN_PRINT("unknown message " + p_msg);
+ }
}
}
@@ -847,6 +869,7 @@ void ScriptEditorDebugger::start(Ref<RemoteDebuggerPeer> p_peer) {
tabs->set_current_tab(0);
_set_reason_text(TTR("Debug session started."), MESSAGE_SUCCESS);
_update_buttons_state();
+ emit_signal("started");
}
void ScriptEditorDebugger::_update_buttons_state() {
@@ -1395,6 +1418,7 @@ void ScriptEditorDebugger::_bind_methods() {
ClassDB::bind_method(D_METHOD("request_remote_object", "id"), &ScriptEditorDebugger::request_remote_object);
ClassDB::bind_method(D_METHOD("update_remote_object", "id", "property", "value"), &ScriptEditorDebugger::update_remote_object);
+ ADD_SIGNAL(MethodInfo("started"));
ADD_SIGNAL(MethodInfo("stopped"));
ADD_SIGNAL(MethodInfo("stop_requested"));
ADD_SIGNAL(MethodInfo("stack_frame_selected", PropertyInfo(Variant::INT, "frame")));
@@ -1408,6 +1432,43 @@ void ScriptEditorDebugger::_bind_methods() {
ADD_SIGNAL(MethodInfo("remote_tree_updated"));
}
+void ScriptEditorDebugger::add_debugger_plugin(const Ref<Script> &p_script) {
+ if (!debugger_plugins.has(p_script)) {
+ EditorDebuggerPlugin *plugin = memnew(EditorDebuggerPlugin());
+ plugin->attach_debugger(this);
+ plugin->set_script(p_script);
+ tabs->add_child(plugin);
+ debugger_plugins.insert(p_script, plugin);
+ }
+}
+
+void ScriptEditorDebugger::remove_debugger_plugin(const Ref<Script> &p_script) {
+ if (debugger_plugins.has(p_script)) {
+ tabs->remove_child(debugger_plugins[p_script]);
+ debugger_plugins[p_script]->detach_debugger(false);
+ memdelete(debugger_plugins[p_script]);
+ debugger_plugins.erase(p_script);
+ }
+}
+
+void ScriptEditorDebugger::send_message(const String &p_message, const Array &p_args) {
+ _put_msg(p_message, p_args);
+}
+
+void ScriptEditorDebugger::register_message_capture(const StringName &p_name, const Callable &p_callable) {
+ ERR_FAIL_COND_MSG(has_capture(p_name), "Capture already registered: " + p_name);
+ captures.insert(p_name, p_callable);
+}
+
+void ScriptEditorDebugger::unregister_message_capture(const StringName &p_name) {
+ ERR_FAIL_COND_MSG(!has_capture(p_name), "Capture not registered: " + p_name);
+ captures.erase(p_name);
+}
+
+bool ScriptEditorDebugger::has_capture(const StringName &p_name) {
+ return captures.has(p_name);
+}
+
ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
editor = p_editor;
diff --git a/editor/debugger/script_editor_debugger.h b/editor/debugger/script_editor_debugger.h
index 6e5699e929..56b34e8e8c 100644
--- a/editor/debugger/script_editor_debugger.h
+++ b/editor/debugger/script_editor_debugger.h
@@ -54,6 +54,7 @@ class EditorVisualProfiler;
class EditorNetworkProfiler;
class EditorPerformanceProfiler;
class SceneDebuggerTree;
+class EditorDebuggerPlugin;
class ScriptEditorDebugger : public MarginContainer {
GDCLASS(ScriptEditorDebugger, MarginContainer);
@@ -146,6 +147,10 @@ private:
EditorDebuggerNode::CameraOverride camera_override;
+ Map<Ref<Script>, EditorDebuggerPlugin *> debugger_plugins;
+
+ Map<StringName, Callable> captures;
+
void _stack_dump_frame_selected();
void _file_selected(const String &p_file);
@@ -253,6 +258,16 @@ public:
bool is_skip_breakpoints();
virtual Size2 get_minimum_size() const override;
+
+ void add_debugger_plugin(const Ref<Script> &p_script);
+ void remove_debugger_plugin(const Ref<Script> &p_script);
+
+ void send_message(const String &p_message, const Array &p_args);
+
+ void register_message_capture(const StringName &p_name, const Callable &p_callable);
+ void unregister_message_capture(const StringName &p_name);
+ bool has_capture(const StringName &p_name);
+
ScriptEditorDebugger(EditorNode *p_editor = nullptr);
~ScriptEditorDebugger();
};
diff --git a/editor/editor_audio_buses.h b/editor/editor_audio_buses.h
index 87c060d1f5..b6cf1183b5 100644
--- a/editor/editor_audio_buses.h
+++ b/editor/editor_audio_buses.h
@@ -230,7 +230,7 @@ private:
render_db_value = n.render_db_value;
}
- _FORCE_INLINE_ AudioNotch operator=(const EditorAudioMeterNotches::AudioNotch &n) {
+ _FORCE_INLINE_ AudioNotch &operator=(const EditorAudioMeterNotches::AudioNotch &n) {
relative_position = n.relative_position;
db_value = n.db_value;
render_db_value = n.render_db_value;
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index 130c330f5a..5118ccacad 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -262,7 +262,9 @@ EditorHistory::EditorHistory() {
}
EditorPlugin *EditorData::get_editor(Object *p_object) {
- for (int i = 0; i < editor_plugins.size(); i++) {
+ // We need to iterate backwards so that we can check user-created plugins first.
+ // Otherwise, it would not be possible for plugins to handle CanvasItem and Spatial nodes.
+ for (int i = editor_plugins.size() - 1; i > -1; i--) {
if (editor_plugins[i]->has_main_screen() && editor_plugins[i]->handles(p_object)) {
return editor_plugins[i];
}
@@ -272,7 +274,7 @@ EditorPlugin *EditorData::get_editor(Object *p_object) {
}
EditorPlugin *EditorData::get_subeditor(Object *p_object) {
- for (int i = 0; i < editor_plugins.size(); i++) {
+ for (int i = editor_plugins.size() - 1; i > -1; i--) {
if (!editor_plugins[i]->has_main_screen() && editor_plugins[i]->handles(p_object)) {
return editor_plugins[i];
}
@@ -283,7 +285,7 @@ EditorPlugin *EditorData::get_subeditor(Object *p_object) {
Vector<EditorPlugin *> EditorData::get_subeditors(Object *p_object) {
Vector<EditorPlugin *> sub_plugins;
- for (int i = 0; i < editor_plugins.size(); i++) {
+ for (int i = editor_plugins.size() - 1; i > -1; i--) {
if (!editor_plugins[i]->has_main_screen() && editor_plugins[i]->handles(p_object)) {
sub_plugins.push_back(editor_plugins[i]);
}
@@ -292,7 +294,7 @@ Vector<EditorPlugin *> EditorData::get_subeditors(Object *p_object) {
}
EditorPlugin *EditorData::get_editor(String p_name) {
- for (int i = 0; i < editor_plugins.size(); i++) {
+ for (int i = editor_plugins.size() - 1; i > -1; i--) {
if (editor_plugins[i]->get_name() == p_name) {
return editor_plugins[i];
}
diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp
index f68cc3b323..7335563dd9 100644
--- a/editor/editor_feature_profile.cpp
+++ b/editor/editor_feature_profile.cpp
@@ -41,9 +41,9 @@ const char *EditorFeatureProfile::feature_names[FEATURE_MAX] = {
TTRC("Script Editor"),
TTRC("Asset Library"),
TTRC("Scene Tree Editing"),
- TTRC("Import Dock"),
TTRC("Node Dock"),
- TTRC("FileSystem and Import Docks")
+ TTRC("FileSystem Dock"),
+ TTRC("Import Dock"),
};
const char *EditorFeatureProfile::feature_identifiers[FEATURE_MAX] = {
@@ -51,9 +51,9 @@ const char *EditorFeatureProfile::feature_identifiers[FEATURE_MAX] = {
"script",
"asset_lib",
"scene_tree",
- "import_dock",
"node_dock",
- "filesystem_dock"
+ "filesystem_dock",
+ "import_dock",
};
void EditorFeatureProfile::set_disable_class(const StringName &p_class, bool p_disabled) {
@@ -271,9 +271,9 @@ void EditorFeatureProfile::_bind_methods() {
BIND_ENUM_CONSTANT(FEATURE_SCRIPT);
BIND_ENUM_CONSTANT(FEATURE_ASSET_LIB);
BIND_ENUM_CONSTANT(FEATURE_SCENE_TREE);
- BIND_ENUM_CONSTANT(FEATURE_IMPORT_DOCK);
BIND_ENUM_CONSTANT(FEATURE_NODE_DOCK);
BIND_ENUM_CONSTANT(FEATURE_FILESYSTEM_DOCK);
+ BIND_ENUM_CONSTANT(FEATURE_IMPORT_DOCK);
BIND_ENUM_CONSTANT(FEATURE_MAX);
}
@@ -678,9 +678,16 @@ void EditorFeatureProfileManager::_update_selected_profile() {
TreeItem *root = class_list->create_item();
TreeItem *features = class_list->create_item(root);
+ TreeItem *last_feature;
features->set_text(0, TTR("Enabled Features:"));
for (int i = 0; i < EditorFeatureProfile::FEATURE_MAX; i++) {
- TreeItem *feature = class_list->create_item(features);
+ TreeItem *feature;
+ if (i == EditorFeatureProfile::FEATURE_IMPORT_DOCK) {
+ feature = class_list->create_item(last_feature);
+ } else {
+ feature = class_list->create_item(features);
+ last_feature = feature;
+ }
feature->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
feature->set_text(0, TTRGET(EditorFeatureProfile::get_feature_name(EditorFeatureProfile::Feature(i))));
feature->set_selectable(0, true);
diff --git a/editor/editor_feature_profile.h b/editor/editor_feature_profile.h
index 38413e35a2..d0d08c61f4 100644
--- a/editor/editor_feature_profile.h
+++ b/editor/editor_feature_profile.h
@@ -49,9 +49,9 @@ public:
FEATURE_SCRIPT,
FEATURE_ASSET_LIB,
FEATURE_SCENE_TREE,
- FEATURE_IMPORT_DOCK,
FEATURE_NODE_DOCK,
FEATURE_FILESYSTEM_DOCK,
+ FEATURE_IMPORT_DOCK,
FEATURE_MAX
};
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index bce34db740..30aebd2b1f 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -244,7 +244,7 @@ void EditorHelp::_add_method(const DocData::MethodDoc &p_method, bool p_overview
class_desc->push_cell();
class_desc->push_align(RichTextLabel::ALIGN_RIGHT);
} else {
- static const CharType prefix[3] = { 0x25CF /* filled circle */, ' ', 0 };
+ static const char32_t prefix[3] = { 0x25CF /* filled circle */, ' ', 0 };
class_desc->add_text(String(prefix));
}
@@ -761,7 +761,7 @@ void EditorHelp::_update_doc() {
signal_line[cd.signals[i].name] = class_desc->get_line_count() - 2; //gets overridden if description
class_desc->push_font(doc_code_font); // monofont
class_desc->push_color(headline_color);
- static const CharType prefix[3] = { 0x25CF /* filled circle */, ' ', 0 };
+ static const char32_t prefix[3] = { 0x25CF /* filled circle */, ' ', 0 };
class_desc->add_text(String(prefix));
_add_text(cd.signals[i].name);
class_desc->pop();
@@ -876,7 +876,7 @@ void EditorHelp::_update_doc() {
class_desc->push_font(doc_code_font);
class_desc->push_color(headline_color);
- static const CharType prefix[3] = { 0x25CF /* filled circle */, ' ', 0 };
+ static const char32_t prefix[3] = { 0x25CF /* filled circle */, ' ', 0 };
class_desc->add_text(String(prefix));
_add_text(enum_list[i].name);
class_desc->pop();
@@ -890,7 +890,7 @@ void EditorHelp::_update_doc() {
if (enum_list[i].description != "") {
class_desc->push_font(doc_font);
class_desc->push_color(comment_color);
- static const CharType dash[6] = { ' ', ' ', 0x2013 /* en dash */, ' ', ' ', 0 };
+ static const char32_t dash[6] = { ' ', ' ', 0x2013 /* en dash */, ' ', ' ', 0 };
class_desc->add_text(String(dash));
_add_text(DTR(enum_list[i].description));
class_desc->pop();
@@ -937,12 +937,12 @@ void EditorHelp::_update_doc() {
Vector<float> color = stripped.split_floats(",");
if (color.size() >= 3) {
class_desc->push_color(Color(color[0], color[1], color[2]));
- static const CharType prefix[3] = { 0x25CF /* filled circle */, ' ', 0 };
+ static const char32_t prefix[3] = { 0x25CF /* filled circle */, ' ', 0 };
class_desc->add_text(String(prefix));
class_desc->pop();
}
} else {
- static const CharType prefix[3] = { 0x25CF /* filled circle */, ' ', 0 };
+ static const char32_t prefix[3] = { 0x25CF /* filled circle */, ' ', 0 };
class_desc->add_text(String(prefix));
}
@@ -960,7 +960,7 @@ void EditorHelp::_update_doc() {
if (constants[i].description != "") {
class_desc->push_font(doc_font);
class_desc->push_color(comment_color);
- static const CharType dash[6] = { ' ', ' ', 0x2013 /* en dash */, ' ', ' ', 0 };
+ static const char32_t dash[6] = { ' ', ' ', 0x2013 /* en dash */, ' ', ' ', 0 };
class_desc->add_text(String(dash));
_add_text(DTR(constants[i].description));
class_desc->pop();
@@ -1002,7 +1002,7 @@ void EditorHelp::_update_doc() {
class_desc->push_cell();
class_desc->push_font(doc_code_font);
- static const CharType prefix[3] = { 0x25CF /* filled circle */, ' ', 0 };
+ static const char32_t prefix[3] = { 0x25CF /* filled circle */, ' ', 0 };
class_desc->add_text(String(prefix));
_add_type(cd.properties[i].type, cd.properties[i].enumeration);
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 2e716a636e..336e34298f 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -1969,7 +1969,7 @@ void EditorInspector::refresh() {
if (refresh_countdown > 0 || changing) {
return;
}
- refresh_countdown = EditorSettings::get_singleton()->get("docks/property_editor/auto_refresh_interval");
+ refresh_countdown = refresh_interval_cache;
}
Object *EditorInspector::get_edited_object() {
@@ -2332,6 +2332,8 @@ void EditorInspector::_node_removed(Node *p_node) {
void EditorInspector::_notification(int p_what) {
if (p_what == NOTIFICATION_READY) {
EditorFeatureProfileManager::get_singleton()->connect("current_feature_profile_changed", callable_mp(this, &EditorInspector::_feature_profile_changed));
+ refresh_interval_cache = EDITOR_GET("docks/property_editor/auto_refresh_interval");
+ refresh_countdown = refresh_interval_cache;
}
if (p_what == NOTIFICATION_ENTER_TREE) {
@@ -2367,6 +2369,9 @@ void EditorInspector::_notification(int p_what) {
}
}
}
+ } else {
+ // Restart countdown if <= 0
+ refresh_countdown = refresh_interval_cache;
}
changing++;
@@ -2399,6 +2404,9 @@ void EditorInspector::_notification(int p_what) {
add_theme_style_override("bg", get_theme_stylebox("bg", "Tree"));
}
+ refresh_interval_cache = EDITOR_GET("docks/property_editor/auto_refresh_interval");
+ refresh_countdown = refresh_interval_cache;
+
update_tree();
}
}
@@ -2562,6 +2570,7 @@ EditorInspector::EditorInspector() {
update_all_pending = false;
update_tree_pending = false;
refresh_countdown = 0;
+ refresh_interval_cache = 0;
read_only = false;
search_box = nullptr;
keying = false;
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index 36b80a7dd4..d1046315f4 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -294,6 +294,7 @@ class EditorInspector : public ScrollContainer {
bool deletable_properties;
float refresh_countdown;
+ float refresh_interval_cache;
bool update_tree_pending;
StringName _prop_edited;
StringName property_selected;
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 381ff88890..e90f30496c 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -123,6 +123,7 @@
#include "editor/plugins/cpu_particles_3d_editor_plugin.h"
#include "editor/plugins/curve_editor_plugin.h"
#include "editor/plugins/debugger_editor_plugin.h"
+#include "editor/plugins/editor_debugger_plugin.h"
#include "editor/plugins/editor_preview_plugins.h"
#include "editor/plugins/gi_probe_editor_plugin.h"
#include "editor/plugins/gpu_particles_2d_editor_plugin.h"
@@ -456,8 +457,6 @@ void EditorNode::_notification(int p_what) {
editor_selection->update();
- //scene_root->set_size_override(true, Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height")));
-
{ //TODO should only happen on settings changed
int current_filter = GLOBAL_GET("rendering/canvas_textures/default_texture_filter");
if (current_filter != scene_root->get_default_canvas_item_texture_filter()) {
@@ -479,6 +478,8 @@ void EditorNode::_notification(int p_what) {
RS::get_singleton()->screen_space_roughness_limiter_set_active(GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_enabled"), GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_amount"), GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_limit"));
bool glow_bicubic = int(GLOBAL_GET("rendering/quality/glow/upscale_mode")) > 0;
RS::get_singleton()->environment_glow_set_use_bicubic_upscale(glow_bicubic);
+ bool glow_high_quality = GLOBAL_GET("rendering/quality/glow/use_high_quality");
+ RS::get_singleton()->environment_glow_set_use_high_quality(glow_high_quality);
RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/quality/screen_space_reflection/roughness_quality")));
RS::get_singleton()->environment_set_ssr_roughness_quality(ssr_roughness_quality);
RS::SubSurfaceScatteringQuality sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_quality")));
@@ -2624,6 +2625,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case SETTINGS_TOGGLE_CONSOLE: {
bool was_visible = DisplayServer::get_singleton()->is_console_visible();
DisplayServer::get_singleton()->console_set_visible(!was_visible);
+ EditorSettings::get_singleton()->set_setting("interface/editor/hide_console_window", was_visible);
} break;
case EDITOR_SCREENSHOT: {
screenshot_timer->start();
@@ -3622,6 +3624,7 @@ void EditorNode::register_editor_types() {
// FIXME: Is this stuff obsolete, or should it be ported to new APIs?
ClassDB::register_class<EditorScenePostImport>();
//ClassDB::register_type<EditorImportExport>();
+ ClassDB::register_class<EditorDebuggerPlugin>();
}
void EditorNode::unregister_editor_types() {
@@ -5344,9 +5347,11 @@ void EditorNode::_feature_profile_changed() {
TabContainer *node_tabs = cast_to<TabContainer>(node_dock->get_parent());
TabContainer *fs_tabs = cast_to<TabContainer>(filesystem_dock->get_parent());
if (profile.is_valid()) {
- import_tabs->set_tab_hidden(import_dock->get_index(), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_IMPORT_DOCK));
node_tabs->set_tab_hidden(node_dock->get_index(), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_NODE_DOCK));
- fs_tabs->set_tab_hidden(filesystem_dock->get_index(), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_FILESYSTEM_DOCK));
+ // The Import dock is useless without the FileSystem dock. Ensure the configuration is valid.
+ bool fs_dock_disabled = profile->is_feature_disabled(EditorFeatureProfile::FEATURE_FILESYSTEM_DOCK);
+ fs_tabs->set_tab_hidden(filesystem_dock->get_index(), fs_dock_disabled);
+ import_tabs->set_tab_hidden(import_dock->get_index(), fs_dock_disabled || profile->is_feature_disabled(EditorFeatureProfile::FEATURE_IMPORT_DOCK));
main_editor_buttons[EDITOR_3D]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D));
main_editor_buttons[EDITOR_SCRIPT]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_SCRIPT));
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index da0a0827d2..bce46b719a 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -811,6 +811,14 @@ ScriptCreateDialog *EditorPlugin::get_script_create_dialog() {
return EditorNode::get_singleton()->get_script_create_dialog();
}
+void EditorPlugin::add_debugger_plugin(const Ref<Script> &p_script) {
+ EditorDebuggerNode::get_singleton()->add_debugger_plugin(p_script);
+}
+
+void EditorPlugin::remove_debugger_plugin(const Ref<Script> &p_script) {
+ EditorDebuggerNode::get_singleton()->remove_debugger_plugin(p_script);
+}
+
void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_control_to_container", "container", "control"), &EditorPlugin::add_control_to_container);
ClassDB::bind_method(D_METHOD("add_control_to_bottom_panel", "control", "title"), &EditorPlugin::add_control_to_bottom_panel);
@@ -851,6 +859,8 @@ void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_editor_interface"), &EditorPlugin::get_editor_interface);
ClassDB::bind_method(D_METHOD("get_script_create_dialog"), &EditorPlugin::get_script_create_dialog);
+ ClassDB::bind_method(D_METHOD("add_debugger_plugin", "script"), &EditorPlugin::add_debugger_plugin);
+ ClassDB::bind_method(D_METHOD("remove_debugger_plugin", "script"), &EditorPlugin::remove_debugger_plugin);
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_canvas_gui_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_canvas_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control")));
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 685f69bf3f..c7803f73c9 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -33,6 +33,7 @@
#include "core/io/config_file.h"
#include "core/undo_redo.h"
+#include "editor/debugger/editor_debugger_node.h"
#include "editor/editor_inspector.h"
#include "editor/editor_translation_parser.h"
#include "editor/import/editor_import_plugin.h"
@@ -249,6 +250,9 @@ public:
void add_autoload_singleton(const String &p_name, const String &p_path);
void remove_autoload_singleton(const String &p_name);
+ void add_debugger_plugin(const Ref<Script> &p_script);
+ void remove_debugger_plugin(const Ref<Script> &p_script);
+
void enable_plugin();
void disable_plugin();
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index d5cc9ac5c1..4c8af615b4 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -36,6 +36,7 @@
#include "editor_properties_array_dict.h"
#include "editor_scale.h"
#include "scene/main/window.h"
+#include "scene/resources/dynamic_font.h"
///////////////////// NULL /////////////////////////
@@ -3014,6 +3015,8 @@ bool EditorPropertyResource::_is_drop_valid(const Dictionary &p_drag_data) const
allowed_types.append("Texture2D");
} else if (at == "ShaderMaterial") {
allowed_types.append("Shader");
+ } else if (at == "Font") {
+ allowed_types.append("DynamicFontData");
}
}
@@ -3111,6 +3114,13 @@ void EditorPropertyResource::drop_data_fw(const Point2 &p_point, const Variant &
res = mat;
break;
}
+
+ if (at == "Font" && ClassDB::is_parent_class(res->get_class(), "DynamicFontData")) {
+ Ref<DynamicFont> font = memnew(DynamicFont);
+ font->set_font_data(res);
+ res = font;
+ break;
+ }
}
}
diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp
index b49c50fa31..7fada633c9 100644
--- a/editor/editor_run.cpp
+++ b/editor/editor_run.cpp
@@ -192,9 +192,9 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
String exec = OS::get_singleton()->get_executable_path();
- printf("Running: %ls", exec.c_str());
+ printf("Running: %s", exec.utf8().get_data());
for (List<String>::Element *E = args.front(); E; E = E->next()) {
- printf(" %ls", E->get().c_str());
+ printf(" %s", E->get().utf8().get_data());
};
printf("\n");
diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp
index 9a834977fd..422534a2e1 100644
--- a/editor/editor_run_native.cpp
+++ b/editor/editor_run_native.cpp
@@ -121,7 +121,7 @@ void EditorRunNative::_run_native(int p_idx, int p_platform) {
}
if (preset.is_null()) {
- EditorNode::get_singleton()->show_warning(TTR("No runnable export preset found for this platform.\nPlease add a runnable preset in the export menu."));
+ EditorNode::get_singleton()->show_warning(TTR("No runnable export preset found for this platform.\nPlease add a runnable preset in the Export menu or define an existing preset as runnable."));
return;
}
diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp
index eabbf6b0d8..cf19b54cff 100644
--- a/editor/editor_sectioned_inspector.cpp
+++ b/editor/editor_sectioned_inspector.cpp
@@ -238,7 +238,7 @@ void SectionedInspector::update_category_list() {
continue;
}
- if (!filter.empty() && !filter.is_subsequence_ofi(pi.name) && !filter.is_subsequence_ofi(pi.name.replace("/", " ").capitalize())) {
+ if (!filter.empty() && pi.name.findn(filter) == -1 && pi.name.replace("/", " ").capitalize().findn(filter) == -1) {
continue;
}
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 7b24e6967a..0aefef7018 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -334,6 +334,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("interface/editor/automatically_open_screenshots", true);
_initial_set("interface/editor/single_window_mode", false);
hints["interface/editor/single_window_mode"] = PropertyInfo(Variant::BOOL, "interface/editor/single_window_mode", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
+ _initial_set("interface/editor/hide_console_window", false);
_initial_set("interface/editor/save_each_scene_on_quit", true); // Regression
_initial_set("interface/editor/quit_confirmation", true);
@@ -935,6 +936,7 @@ void EditorSettings::create() {
String config_file_name = "editor_settings-" + itos(VERSION_MAJOR) + ".tres";
config_file_path = config_dir.plus_file(config_file_name);
if (!dir->file_exists(config_file_name)) {
+ memdelete(dir);
goto fail;
}
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 31903c89be..0071f169ac 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -2300,6 +2300,7 @@ void FileSystemDock::_tree_rmb_select(const Vector2 &p_pos) {
// Right click is pressed in the tree.
Vector<String> paths = _tree_get_selected(false);
+ tree_popup->clear();
if (paths.size() == 1) {
if (paths[0].ends_with("/")) {
tree_popup->add_icon_item(get_theme_icon("GuiTreeArrowDown", "EditorIcons"), TTR("Expand All"), FOLDER_EXPAND_ALL);
@@ -2310,7 +2311,6 @@ void FileSystemDock::_tree_rmb_select(const Vector2 &p_pos) {
// Popup.
if (!paths.empty()) {
- tree_popup->clear();
tree_popup->set_size(Size2(1, 1));
_file_and_folders_fill_popup(tree_popup, paths);
tree_popup->set_position(tree->get_screen_position() + p_pos);
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index bd4bb57dcf..c2ccbdb08c 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -54,7 +54,7 @@ inline void pop_back(T &container) {
}
// TODO Copied from TextEdit private, would be nice to extract it in a single place
-static bool is_text_char(CharType c) {
+static bool is_text_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
@@ -854,7 +854,7 @@ public:
String get_line(FileAccess *f) {
_line_buffer.clear();
- CharType c = f->get_8();
+ char32_t c = f->get_8();
while (!f->eof_reached()) {
if (c == '\n') {
diff --git a/editor/input_map_editor.cpp b/editor/input_map_editor.cpp
index 52cf9c1869..c67e16d371 100644
--- a/editor/input_map_editor.cpp
+++ b/editor/input_map_editor.cpp
@@ -100,7 +100,7 @@ void InputMapEditor::_notification(int p_what) {
}
static bool _validate_action_name(const String &p_name) {
- const CharType *cstr = p_name.c_str();
+ const char32_t *cstr = p_name.get_data();
for (int i = 0; cstr[i]; i++) {
if (cstr[i] == '/' || cstr[i] == ':' || cstr[i] == '"' ||
cstr[i] == '=' || cstr[i] == '\\' || cstr[i] < 32) {
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index 49e67f3605..7a3fb1ff52 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -287,7 +287,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
pre_move_edit = vertices2;
edited_point = PosVertex(insert.polygon, insert.vertex + 1, xform.affine_inverse().xform(insert.pos));
vertices2.insert(edited_point.vertex, edited_point.pos);
- selected_point = edited_point;
+ selected_point = Vertex(edited_point.polygon, edited_point.vertex);
edge_point = PosVertex();
undo_redo->create_action(TTR("Insert Point"));
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 3f9f159d7f..9427f82f9e 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -6256,7 +6256,7 @@ void CanvasItemEditorViewport::_perform_drop_data() {
files_str += error_files[i].get_file().get_basename() + ",";
}
files_str = files_str.substr(0, files_str.length() - 1);
- accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.c_str()));
+ accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.get_data()));
accept->popup_centered();
}
}
diff --git a/editor/plugins/debugger_editor_plugin.cpp b/editor/plugins/debugger_editor_plugin.cpp
index 0a4d173923..0747e42045 100644
--- a/editor/plugins/debugger_editor_plugin.cpp
+++ b/editor/plugins/debugger_editor_plugin.cpp
@@ -47,7 +47,7 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(EditorNode *p_editor, MenuButton *p_d
ED_SHORTCUT("debugger/keep_debugger_open", TTR("Keep Debugger Open"));
ED_SHORTCUT("debugger/debug_with_external_editor", TTR("Debug with External Editor"));
- // File Server for deploy with remote fs.
+ // File Server for deploy with remote filesystem.
file_server = memnew(EditorFileServer);
EditorDebuggerNode *debugger = memnew(EditorDebuggerNode);
@@ -59,19 +59,31 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(EditorNode *p_editor, MenuButton *p_d
PopupMenu *p = debug_menu->get_popup();
p->set_hide_on_checkable_item_selection(false);
p->add_check_shortcut(ED_SHORTCUT("editor/deploy_with_remote_debug", TTR("Deploy with Remote Debug")), RUN_DEPLOY_REMOTE_DEBUG);
- p->set_item_tooltip(p->get_item_count() - 1, TTR("When exporting or deploying, the resulting executable will attempt to connect to the IP of this computer in order to be debugged."));
- p->add_check_shortcut(ED_SHORTCUT("editor/small_deploy_with_network_fs", TTR("Small Deploy with Network FS")), RUN_FILE_SERVER);
- p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is enabled, export or deploy will produce a minimal executable.\nThe filesystem will be provided from the project by the editor over the network.\nOn Android, deploy will use the USB cable for faster performance. This option speeds up testing for games with a large footprint."));
+ p->set_item_tooltip(
+ p->get_item_count() - 1,
+ TTR("When this option is enabled, using one-click deploy will make the executable attempt to connect to this computer's IP so the running project can be debugged.\nThis option is intended to be used for remote debugging (typically with a mobile device).\nYou don't need to enable it to use the GDScript debugger locally."));
+ p->add_check_shortcut(ED_SHORTCUT("editor/small_deploy_with_network_fs", TTR("Small Deploy with Network Filesystem")), RUN_FILE_SERVER);
+ p->set_item_tooltip(
+ p->get_item_count() - 1,
+ TTR("When this option is enabled, using one-click deploy for Android will only export an executable without the project data.\nThe filesystem will be provided from the project by the editor over the network.\nOn Android, deploying will use the USB cable for faster performance. This option speeds up testing for projects with large assets."));
p->add_separator();
p->add_check_shortcut(ED_SHORTCUT("editor/visible_collision_shapes", TTR("Visible Collision Shapes")), RUN_DEBUG_COLLISONS);
- p->set_item_tooltip(p->get_item_count() - 1, TTR("Collision shapes and raycast nodes (for 2D and 3D) will be visible on the running game if this option is turned on."));
+ p->set_item_tooltip(
+ p->get_item_count() - 1,
+ TTR("When this option is enabled, collision shapes and raycast nodes (for 2D and 3D) will be visible in the running project."));
p->add_check_shortcut(ED_SHORTCUT("editor/visible_navigation", TTR("Visible Navigation")), RUN_DEBUG_NAVIGATION);
- p->set_item_tooltip(p->get_item_count() - 1, TTR("Navigation meshes and polygons will be visible on the running game if this option is turned on."));
+ p->set_item_tooltip(
+ p->get_item_count() - 1,
+ TTR("When this option is enabled, navigation meshes and polygons will be visible in the running project."));
p->add_separator();
- p->add_check_shortcut(ED_SHORTCUT("editor/sync_scene_changes", TTR("Sync Scene Changes")), RUN_LIVE_DEBUG);
- p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is turned on, any changes made to the scene in the editor will be replicated in the running game.\nWhen used remotely on a device, this is more efficient with network filesystem."));
- p->add_check_shortcut(ED_SHORTCUT("editor/sync_script_changes", TTR("Sync Script Changes")), RUN_RELOAD_SCRIPTS);
- p->set_item_tooltip(p->get_item_count() - 1, TTR("When this option is turned on, any script that is saved will be reloaded on the running game.\nWhen used remotely on a device, this is more efficient with network filesystem."));
+ p->add_check_shortcut(ED_SHORTCUT("editor/sync_scene_changes", TTR("Synchronize Scene Changes")), RUN_LIVE_DEBUG);
+ p->set_item_tooltip(
+ p->get_item_count() - 1,
+ TTR("When this option is enabled, any changes made to the scene in the editor will be replicated in the running project.\nWhen used remotely on a device, this is more efficient when the network filesystem option is enabled."));
+ p->add_check_shortcut(ED_SHORTCUT("editor/sync_script_changes", TTR("Synchronize Script Changes")), RUN_RELOAD_SCRIPTS);
+ p->set_item_tooltip(
+ p->get_item_count() - 1,
+ TTR("When this option is enabled, any script that is saved will be reloaded in the running project.\nWhen used remotely on a device, this is more efficient when the network filesystem option is enabled."));
// Multi-instance, start/stop
instances_menu = memnew(PopupMenu);
diff --git a/editor/plugins/editor_debugger_plugin.cpp b/editor/plugins/editor_debugger_plugin.cpp
new file mode 100644
index 0000000000..b775e871e2
--- /dev/null
+++ b/editor/plugins/editor_debugger_plugin.cpp
@@ -0,0 +1,124 @@
+/*************************************************************************/
+/* editor_debugger_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "editor_debugger_plugin.h"
+
+#include "editor/debugger/script_editor_debugger.h"
+
+void EditorDebuggerPlugin::_breaked(bool p_really_did, bool p_can_debug) {
+ if (p_really_did) {
+ emit_signal("breaked", p_can_debug);
+ } else {
+ emit_signal("continued");
+ }
+}
+
+void EditorDebuggerPlugin::_started() {
+ emit_signal("started");
+}
+
+void EditorDebuggerPlugin::_stopped() {
+ emit_signal("stopped");
+}
+
+void EditorDebuggerPlugin::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("send_message", "message", "data"), &EditorDebuggerPlugin::send_message);
+ ClassDB::bind_method(D_METHOD("register_message_capture", "name", "callable"), &EditorDebuggerPlugin::register_message_capture);
+ ClassDB::bind_method(D_METHOD("unregister_message_capture", "name"), &EditorDebuggerPlugin::unregister_message_capture);
+ ClassDB::bind_method(D_METHOD("has_capture", "name"), &EditorDebuggerPlugin::has_capture);
+ ClassDB::bind_method(D_METHOD("is_breaked"), &EditorDebuggerPlugin::is_breaked);
+ ClassDB::bind_method(D_METHOD("is_debuggable"), &EditorDebuggerPlugin::is_debuggable);
+ ClassDB::bind_method(D_METHOD("is_session_active"), &EditorDebuggerPlugin::is_session_active);
+
+ ADD_SIGNAL(MethodInfo("started"));
+ ADD_SIGNAL(MethodInfo("stopped"));
+ ADD_SIGNAL(MethodInfo("breaked", PropertyInfo(Variant::BOOL, "can_debug")));
+ ADD_SIGNAL(MethodInfo("continued"));
+}
+
+void EditorDebuggerPlugin::attach_debugger(ScriptEditorDebugger *p_debugger) {
+ debugger = p_debugger;
+ if (debugger) {
+ debugger->connect("started", callable_mp(this, &EditorDebuggerPlugin::_started));
+ debugger->connect("stopped", callable_mp(this, &EditorDebuggerPlugin::_stopped));
+ debugger->connect("breaked", callable_mp(this, &EditorDebuggerPlugin::_breaked));
+ }
+}
+
+void EditorDebuggerPlugin::detach_debugger(bool p_call_debugger) {
+ if (debugger) {
+ debugger->disconnect("started", callable_mp(this, &EditorDebuggerPlugin::_started));
+ debugger->disconnect("stopped", callable_mp(this, &EditorDebuggerPlugin::_stopped));
+ debugger->disconnect("breaked", callable_mp(this, &EditorDebuggerPlugin::_breaked));
+ if (p_call_debugger && get_script_instance()) {
+ debugger->remove_debugger_plugin(get_script_instance()->get_script());
+ }
+ debugger = nullptr;
+ }
+}
+
+void EditorDebuggerPlugin::send_message(const String &p_message, const Array &p_args) {
+ ERR_FAIL_COND_MSG(!debugger, "Plugin is not attached to debugger");
+ debugger->send_message(p_message, p_args);
+}
+
+void EditorDebuggerPlugin::register_message_capture(const StringName &p_name, const Callable &p_callable) {
+ ERR_FAIL_COND_MSG(!debugger, "Plugin is not attached to debugger");
+ debugger->register_message_capture(p_name, p_callable);
+}
+
+void EditorDebuggerPlugin::unregister_message_capture(const StringName &p_name) {
+ ERR_FAIL_COND_MSG(!debugger, "Plugin is not attached to debugger");
+ debugger->unregister_message_capture(p_name);
+}
+
+bool EditorDebuggerPlugin::has_capture(const StringName &p_name) {
+ ERR_FAIL_COND_V_MSG(!debugger, false, "Plugin is not attached to debugger");
+ return debugger->has_capture(p_name);
+}
+
+bool EditorDebuggerPlugin::is_breaked() {
+ ERR_FAIL_COND_V_MSG(!debugger, false, "Plugin is not attached to debugger");
+ return debugger->is_breaked();
+}
+
+bool EditorDebuggerPlugin::is_debuggable() {
+ ERR_FAIL_COND_V_MSG(!debugger, false, "Plugin is not attached to debugger");
+ return debugger->is_debuggable();
+}
+
+bool EditorDebuggerPlugin::is_session_active() {
+ ERR_FAIL_COND_V_MSG(!debugger, false, "Plugin is not attached to debugger");
+ return debugger->is_session_active();
+}
+
+EditorDebuggerPlugin::~EditorDebuggerPlugin() {
+ detach_debugger(true);
+}
diff --git a/editor/plugins/editor_debugger_plugin.h b/editor/plugins/editor_debugger_plugin.h
new file mode 100644
index 0000000000..10fd1151de
--- /dev/null
+++ b/editor/plugins/editor_debugger_plugin.h
@@ -0,0 +1,64 @@
+/*************************************************************************/
+/* editor_debugger_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef EDITOR_DEBUGGER_PLUGIN_H
+#define EDITOR_DEBUGGER_PLUGIN_H
+
+#include "scene/gui/control.h"
+
+class ScriptEditorDebugger;
+
+class EditorDebuggerPlugin : public Control {
+ GDCLASS(EditorDebuggerPlugin, Control);
+
+private:
+ ScriptEditorDebugger *debugger = nullptr;
+
+ void _breaked(bool p_really_did, bool p_can_debug);
+ void _started();
+ void _stopped();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void attach_debugger(ScriptEditorDebugger *p_debugger);
+ void detach_debugger(bool p_call_debugger);
+ void send_message(const String &p_message, const Array &p_args);
+ void register_message_capture(const StringName &p_name, const Callable &p_callable);
+ void unregister_message_capture(const StringName &p_name);
+ bool has_capture(const StringName &p_name);
+ bool is_breaked();
+ bool is_debuggable();
+ bool is_session_active();
+ ~EditorDebuggerPlugin();
+};
+
+#endif // EDITOR_DEBUGGER_PLUGIN_H
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 2889cb50a0..3cf4dc5ac8 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -466,7 +466,7 @@ EditorMaterialPreviewPlugin::~EditorMaterialPreviewPlugin() {
///////////////////////////////////////////////////////////////////////////
-static bool _is_text_char(CharType c) {
+static bool _is_text_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
@@ -525,7 +525,7 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size
bool prev_is_text = false;
bool in_keyword = false;
for (int i = 0; i < code.length(); i++) {
- CharType c = code[i];
+ char32_t c = code[i];
if (c > 32) {
if (col < thumbnail_size) {
Color color = text_color;
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 21a75c2f5d..952487c13c 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -3729,7 +3729,7 @@ void Node3DEditorViewport::_perform_drop_data() {
files_str += error_files[i].get_file().get_basename() + ",";
}
files_str = files_str.substr(0, files_str.length() - 1);
- accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.c_str()));
+ accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.get_data()));
accept->popup_centered();
}
}
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 18942b371c..5007983581 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -995,11 +995,16 @@ SpriteFramesEditor::SpriteFramesEditor() {
animations->connect("item_edited", callable_mp(this, &SpriteFramesEditor::_animation_name_edited));
animations->set_allow_reselect(true);
+ HBoxContainer *hbc_anim_speed = memnew(HBoxContainer);
+ hbc_anim_speed->add_child(memnew(Label(TTR("Speed:"))));
+ vbc_animlist->add_child(hbc_anim_speed);
anim_speed = memnew(SpinBox);
- vbc_animlist->add_margin_child(TTR("Speed (FPS):"), anim_speed);
+ anim_speed->set_suffix(TTR("FPS"));
anim_speed->set_min(0);
anim_speed->set_max(100);
anim_speed->set_step(0.01);
+ anim_speed->set_h_size_flags(SIZE_EXPAND_FILL);
+ hbc_anim_speed->add_child(anim_speed);
anim_speed->connect("value_changed", callable_mp(this, &SpriteFramesEditor::_animation_fps_changed));
anim_loop = memnew(CheckButton);
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 762f42abeb..6e722607f7 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -875,7 +875,7 @@ void TextureRegionEditor::_changed_callback(Object *p_changed, const char *p_pro
if (!is_visible()) {
return;
}
- if (p_prop == StringName("atlas") || p_prop == StringName("texture")) {
+ if (p_prop == StringName("atlas") || p_prop == StringName("texture") || p_prop == StringName("region")) {
_edit_region();
}
}
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 18a107ff75..932ded6938 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -206,8 +206,8 @@ void ThemeEditor::_save_template_cbk(String fname) {
file->store_line("; [value] examples:");
file->store_line("; ");
file->store_line("; Type.item = 6 ; numeric constant. ");
- file->store_line("; Type.item = #FF00FF ; HTML color ");
- file->store_line("; Type.item = #55FF00FF ; HTML color with alpha 55.");
+ file->store_line("; Type.item = #FF00FF ; HTML color (magenta).");
+ file->store_line("; Type.item = #FF00FF55 ; HTML color (magenta with alpha 0x55).");
file->store_line("; Type.item = icon(image.png) ; icon in a png file (relative to theme file).");
file->store_line("; Type.item = font(font.xres) ; font in a resource (relative to theme file).");
file->store_line("; Type.item = sbox(stylebox.xres) ; stylebox in a resource (relative to theme file).");
@@ -629,7 +629,7 @@ ThemeEditor::ThemeEditor() {
ScrollContainer *scroll = memnew(ScrollContainer);
add_child(scroll);
scroll->set_enable_v_scroll(true);
- scroll->set_enable_h_scroll(false);
+ scroll->set_enable_h_scroll(true);
scroll->set_v_size_flags(SIZE_EXPAND_FILL);
MarginContainer *root_container = memnew(MarginContainer);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 53bd1150ec..30ae3dd4bb 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -177,25 +177,12 @@ bool VisualShaderEditor::_is_available(int p_mode) {
case VisualShader::TYPE_LIGHT:
current_mode = 4;
break;
+ case VisualShader::TYPE_COMPUTE:
+ current_mode = 8;
+ break;
default:
break;
}
-
- int temp_mode = 0;
-
- if (p_mode & VisualShader::TYPE_FRAGMENT) {
- temp_mode |= 2;
- }
-
- if (p_mode & VisualShader::TYPE_LIGHT) {
- temp_mode |= 4;
- }
-
- if (temp_mode == 0) {
- temp_mode |= 1;
- }
-
- p_mode = temp_mode;
}
return (p_mode == -1 || (p_mode & current_mode) != 0);
@@ -2432,6 +2419,7 @@ VisualShaderEditor::VisualShaderEditor() {
edit_type->add_item(TTR("Vertex"));
edit_type->add_item(TTR("Fragment"));
edit_type->add_item(TTR("Light"));
+ edit_type->add_item(TTR("Compute"));
edit_type->select(1);
edit_type->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected));
graph->get_zoom_hbox()->add_child(edit_type);
@@ -2613,25 +2601,26 @@ VisualShaderEditor::VisualShaderEditor() {
// INPUT
- // SPATIAL-FOR-ALL
- const String input_param_shader_modes = TTR("'%s' input parameter for all shader modes.");
- add_options.push_back(AddOption("Camera", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "camera"), "camera", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("InvCamera", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "inv_camera"), "inv_camera", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("InvProjection", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "inv_projection"), "inv_projection", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Normal", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "normal"), "normal", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("OutputIsSRGB", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "output_is_srgb"), "output_is_srgb", VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Projection", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "camera"), "projection", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("ViewportSize", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "viewport_size"), "viewport_size", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("World", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "world"), "world", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL));
-
- // CANVASITEM-FOR-ALL
-
- add_options.push_back(AddOption("Alpha", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("Color", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("TexturePixelSize", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "texture_pixel_size"), "texture_pixel_size", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("UV", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_CANVAS_ITEM));
+ // SPATIAL-FOR-ALL (except COMPUTE)
+
+ const String input_param_shader_modes = TTR("'%s' input parameter for vertex/fragment/light shader modes.");
+ add_options.push_back(AddOption("Camera", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "camera"), "camera", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX_FRAGMENT_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("InvCamera", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "inv_camera"), "inv_camera", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX_FRAGMENT_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("InvProjection", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "inv_projection"), "inv_projection", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX_FRAGMENT_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Normal", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "normal"), "normal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX_FRAGMENT_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("OutputIsSRGB", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "output_is_srgb"), "output_is_srgb", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_VERTEX_FRAGMENT_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Projection", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "camera"), "projection", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX_FRAGMENT_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX_FRAGMENT_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ViewportSize", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "viewport_size"), "viewport_size", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX_FRAGMENT_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("World", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "world"), "world", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX_FRAGMENT_LIGHT, Shader::MODE_SPATIAL));
+
+ // CANVASITEM-FOR-ALL (except COMPUTE)
+
+ add_options.push_back(AddOption("Alpha", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX_FRAGMENT_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Color", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX_FRAGMENT_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("TexturePixelSize", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "texture_pixel_size"), "texture_pixel_size", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX_FRAGMENT_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX_FRAGMENT_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("UV", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX_FRAGMENT_LIGHT, Shader::MODE_CANVAS_ITEM));
/////////////////
@@ -2644,124 +2633,125 @@ VisualShaderEditor::VisualShaderEditor() {
const String input_param_for_fragment_shader_mode = TTR("'%s' input parameter for fragment shader mode.");
const String input_param_for_light_shader_mode = TTR("'%s' input parameter for light shader mode.");
const String input_param_for_vertex_shader_mode = TTR("'%s' input parameter for vertex shader mode.");
+ const String input_param_for_compute_shader_mode = TTR("'%s' input parameter for compute shader mode.");
const String input_param_for_vertex_and_fragment_shader_mode = TTR("'%s' input parameter for vertex and fragment shader mode.");
- add_options.push_back(AddOption("Alpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Binormal", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal"), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("DepthTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "depth_texture"), "depth_texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("FrontFacing", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "front_facing"), "front_facing", VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("PointCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("ScreenTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture"), "screen_texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Side", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "side"), "side", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Tangent", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "tangent"), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("UV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("UV2", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv2"), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Vertex", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("View", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view"), "view", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SPATIAL));
-
- add_options.push_back(AddOption("Albedo", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "albedo"), "albedo", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Attenuation", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "attenuation"), "attenuation", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Diffuse", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "diffuse"), "diffuse", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Light", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light"), "light", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color"), "light_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Roughness", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "roughness"), "roughness", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Specular", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "specular"), "specular", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Transmission", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "transmission"), "transmission", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("View", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "view"), "view", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
-
- add_options.push_back(AddOption("Alpha", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Binormal", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal"), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Color", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("ModelView", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "modelview"), "modelview", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size"), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Tangent", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "tangent"), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("UV", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("UV2", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv2"), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Alpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Binormal", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal"), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("DepthTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "depth_texture"), "depth_texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("FrontFacing", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "front_facing"), "front_facing", VisualShaderNode::PORT_TYPE_BOOLEAN, 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", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ScreenTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture"), "screen_texture", VisualShaderNode::PORT_TYPE_SAMPLER, 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", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Side", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "side"), "side", VisualShaderNode::PORT_TYPE_SCALAR, 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", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("UV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("UV2", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv2"), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, 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", VisualShaderNode::PORT_TYPE_VECTOR, 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", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+
+ add_options.push_back(AddOption("Albedo", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "albedo"), "albedo", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Attenuation", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "attenuation"), "attenuation", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Diffuse", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "diffuse"), "diffuse", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Light", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light"), "light", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color"), "light_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Roughness", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "roughness"), "roughness", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Specular", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "specular"), "specular", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Transmission", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "transmission"), "transmission", VisualShaderNode::PORT_TYPE_VECTOR, 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", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
+
+ add_options.push_back(AddOption("Alpha", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Binormal", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal"), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Color", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ModelView", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "modelview"), "modelview", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size"), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Tangent", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_mode, "tangent"), "tangent", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("UV", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("UV2", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "uv2"), "uv2", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
// CANVASITEM INPUTS
- add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("LightPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "light_pass"), "light_pass", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("NormalTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "normal_texture"), "normal_texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("PointCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("ScreenPixelSize", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_pixel_size"), "screen_pixel_size", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("ScreenTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture"), "screen_texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("Texture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "texture"), "texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_CANVAS_ITEM));
-
- add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("LightAlpha", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_alpha"), "light_alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color"), "light_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("LightHeight", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_height"), "light_height", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("LightUV", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_uv"), "light_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("LightVector", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_vec"), "light_vec", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("Normal", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "normal"), "normal", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("PointCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("ScreenUV", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("ShadowAlpha", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow_alpha"), "shadow_alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("ShadowColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow_color"), "shadow_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("ShadowVec", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow_vec"), "shadow_vec", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("Texture", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "texture"), "texture", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_LIGHT, Shader::MODE_CANVAS_ITEM));
-
- add_options.push_back(AddOption("Extra", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "extra"), "extra", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("LightPass", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "light_pass"), "light_pass", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size"), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("Projection", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "projection"), "projection", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("World", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "world"), "world", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("FragCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("LightPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "light_pass"), "light_pass", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("NormalTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "normal_texture"), "normal_texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("PointCoord", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("ScreenPixelSize", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_pixel_size"), "screen_pixel_size", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("ScreenTexture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture"), "screen_texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Texture", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "texture"), "texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
+
+ add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("LightAlpha", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_alpha"), "light_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color"), "light_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("LightHeight", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_height"), "light_height", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("LightUV", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_uv"), "light_uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("LightVector", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_vec"), "light_vec", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Normal", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "normal"), "normal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("PointCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord"), "point_coord", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("ScreenUV", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("ShadowAlpha", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow_alpha"), "shadow_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("ShadowColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow_color"), "shadow_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("ShadowVec", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "shadow_vec"), "shadow_vec", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Texture", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "texture"), "texture", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_LIGHT, Shader::MODE_CANVAS_ITEM));
+
+ add_options.push_back(AddOption("Extra", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "extra"), "extra", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("LightPass", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "light_pass"), "light_pass", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("PointSize", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "point_size"), "point_size", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Projection", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "projection"), "projection", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
+ add_options.push_back(AddOption("World", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "world"), "world", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM));
// PARTICLES INPUTS
- add_options.push_back(AddOption("Active", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "active"), "active", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Alpha", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Color", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Custom", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom"), "custom", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("CustomAlpha", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "custom_alpha"), "custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Delta", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "delta"), "delta", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("EmissionTransform", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "emission_transform"), "emission_transform", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Index", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "index"), "index", VisualShaderNode::PORT_TYPE_SCALAR_INT, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("LifeTime", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "lifetime"), "lifetime", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Restart", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "restart"), "restart", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Time", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Transform", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "transform"), "transform", VisualShaderNode::PORT_TYPE_TRANSFORM, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES));
- add_options.push_back(AddOption("Velocity", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "velocity"), "velocity", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_VERTEX, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Active", "Input", "Compute", "VisualShaderNodeInput", vformat(input_param_for_compute_shader_mode, "active"), "active", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_COMPUTE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Alpha", "Input", "Compute", "VisualShaderNodeInput", vformat(input_param_for_compute_shader_mode, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_COMPUTE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Color", "Input", "Compute", "VisualShaderNodeInput", vformat(input_param_for_compute_shader_mode, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_COMPUTE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Custom", "Input", "Compute", "VisualShaderNodeInput", vformat(input_param_for_compute_shader_mode, "custom"), "custom", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_COMPUTE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("CustomAlpha", "Input", "Compute", "VisualShaderNodeInput", vformat(input_param_for_compute_shader_mode, "custom_alpha"), "custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_COMPUTE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Delta", "Input", "Compute", "VisualShaderNodeInput", vformat(input_param_for_compute_shader_mode, "delta"), "delta", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_COMPUTE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("EmissionTransform", "Input", "Compute", "VisualShaderNodeInput", vformat(input_param_for_compute_shader_mode, "emission_transform"), "emission_transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_COMPUTE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Index", "Input", "Compute", "VisualShaderNodeInput", vformat(input_param_for_compute_shader_mode, "index"), "index", VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_COMPUTE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("LifeTime", "Input", "Compute", "VisualShaderNodeInput", vformat(input_param_for_compute_shader_mode, "lifetime"), "lifetime", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_COMPUTE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Restart", "Input", "Compute", "VisualShaderNodeInput", vformat(input_param_for_compute_shader_mode, "restart"), "restart", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_COMPUTE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Time", "Input", "Compute", "VisualShaderNodeInput", vformat(input_param_for_compute_shader_mode, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_COMPUTE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Transform", "Input", "Compute", "VisualShaderNodeInput", vformat(input_param_for_compute_shader_mode, "transform"), "transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_COMPUTE, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("Velocity", "Input", "Compute", "VisualShaderNodeInput", vformat(input_param_for_compute_shader_mode, "velocity"), "velocity", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_COMPUTE, Shader::MODE_PARTICLES));
// SKY INPUTS
- add_options.push_back(AddOption("AtCubeMapPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "at_cubemap_pass"), "at_cubemap_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("AtHalfResPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "at_half_res_pass"), "at_half_res_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("AtQuarterResPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "at_quarter_res_pass"), "at_quarter_res_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("EyeDir", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "eyedir"), "eyedir", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("HalfResColor", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "half_res_color"), "half_res_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("HalfResAlpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "half_res_alpha"), "half_res_alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light0Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_color"), "light0_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light0Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_direction"), "light0_direction", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light0Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_enabled"), "light0_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light0Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_energy"), "light0_energy", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light1Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_color"), "light1_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light1Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_direction"), "light1_direction", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light1Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_enabled"), "light1_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light1Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_energy"), "light1_energy", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light2Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_color"), "light2_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light2Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_direction"), "light2_direction", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light2Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_enabled"), "light2_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light2Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_energy"), "light2_energy", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light3Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_color"), "light3_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light3Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_direction"), "light3_direction", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light3Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_enabled"), "light3_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Light3Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_energy"), "light3_energy", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Position", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "position"), "position", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("QuarterResColor", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "quarter_res_color"), "quarter_res_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("QuarterResAlpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "quarter_res_alpha"), "quarter_res_alpha", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Radiance", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "radiance"), "radiance", VisualShaderNode::PORT_TYPE_SAMPLER, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("SkyCoords", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "sky_coords"), "sky_coords", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
- add_options.push_back(AddOption("Time", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("AtCubeMapPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "at_cubemap_pass"), "at_cubemap_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("AtHalfResPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "at_half_res_pass"), "at_half_res_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("AtQuarterResPass", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "at_quarter_res_pass"), "at_quarter_res_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("EyeDir", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "eyedir"), "eyedir", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("HalfResColor", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "half_res_color"), "half_res_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("HalfResAlpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "half_res_alpha"), "half_res_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light0Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_color"), "light0_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light0Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_direction"), "light0_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light0Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_enabled"), "light0_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light0Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light0_energy"), "light0_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light1Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_color"), "light1_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light1Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_direction"), "light1_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light1Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_enabled"), "light1_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light1Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light1_energy"), "light1_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light2Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_color"), "light2_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light2Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_direction"), "light2_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light2Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_enabled"), "light2_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light2Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light2_energy"), "light2_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light3Color", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_color"), "light3_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light3Direction", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_direction"), "light3_direction", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light3Enabled", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_enabled"), "light3_enabled", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Light3Energy", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "light3_energy"), "light3_energy", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Position", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "position"), "position", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("QuarterResColor", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "quarter_res_color"), "quarter_res_color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("QuarterResAlpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "quarter_res_alpha"), "quarter_res_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Radiance", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "radiance"), "radiance", VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("ScreenUV", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv"), "screen_uv", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("SkyCoords", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "sky_coords"), "sky_coords", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
+ add_options.push_back(AddOption("Time", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SKY));
// SCALAR
@@ -2853,7 +2843,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("CubeMapUniform", "Textures", "Variables", "VisualShaderNodeCubemapUniform", TTR("Cubic texture uniform lookup."), -1, -1));
add_options.push_back(AddOption("Texture2DArray", "Textures", "Functions", "VisualShaderNodeTexture2DArray", TTR("Perform the 2D-array texture lookup."), -1, -1, -1, -1, -1));
add_options.push_back(AddOption("TextureUniform", "Textures", "Variables", "VisualShaderNodeTextureUniform", TTR("2D texture uniform lookup."), -1, -1));
- add_options.push_back(AddOption("TextureUniformTriplanar", "Textures", "Variables", "VisualShaderNodeTextureUniformTriplanar", TTR("2D texture uniform lookup with triplanar."), -1, -1, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("TextureUniformTriplanar", "Textures", "Variables", "VisualShaderNodeTextureUniformTriplanar", TTR("2D texture uniform lookup with triplanar."), -1, -1, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Texture2DArrayUniform", "Textures", "Variables", "VisualShaderNodeTexture2DArrayUniform", TTR("2D array of textures uniform lookup."), -1, -1, -1, -1, -1));
// TRANSFORM
@@ -2951,15 +2941,15 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("GlobalExpression", "Special", "", "VisualShaderNodeGlobalExpression", TTR("Custom Godot Shader Language expression, which is placed on top of the resulted shader. You can place various function definitions inside and call it later in the Expressions. You can also declare varyings, uniforms and constants.")));
add_options.push_back(AddOption("UniformRef", "Special", "", "VisualShaderNodeUniformRef", TTR("A reference to an existing uniform.")));
- add_options.push_back(AddOption("ScalarDerivativeFunc", "Special", "Common", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) Scalar derivative function."), -1, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true));
- add_options.push_back(AddOption("VectorDerivativeFunc", "Special", "Common", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) Vector derivative function."), -1, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true));
+ add_options.push_back(AddOption("ScalarDerivativeFunc", "Special", "Common", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) Scalar derivative function."), -1, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true));
+ add_options.push_back(AddOption("VectorDerivativeFunc", "Special", "Common", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) Vector derivative function."), -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true));
- add_options.push_back(AddOption("DdX", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'x' using local differencing."), VisualShaderNodeVectorDerivativeFunc::FUNC_X, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true));
- add_options.push_back(AddOption("DdXS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Derivative in 'x' using local differencing."), VisualShaderNodeScalarDerivativeFunc::FUNC_X, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true));
- add_options.push_back(AddOption("DdY", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'y' using local differencing."), VisualShaderNodeVectorDerivativeFunc::FUNC_Y, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true));
- add_options.push_back(AddOption("DdYS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Derivative in 'y' using local differencing."), VisualShaderNodeScalarDerivativeFunc::FUNC_Y, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true));
- add_options.push_back(AddOption("Sum", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and 'y'."), VisualShaderNodeVectorDerivativeFunc::FUNC_SUM, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true));
- add_options.push_back(AddOption("SumS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Sum of absolute derivative in 'x' and 'y'."), VisualShaderNodeScalarDerivativeFunc::FUNC_SUM, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true));
+ add_options.push_back(AddOption("DdX", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'x' using local differencing."), VisualShaderNodeVectorDerivativeFunc::FUNC_X, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true));
+ add_options.push_back(AddOption("DdXS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Derivative in 'x' using local differencing."), VisualShaderNodeScalarDerivativeFunc::FUNC_X, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true));
+ add_options.push_back(AddOption("DdY", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Derivative in 'y' using local differencing."), VisualShaderNodeVectorDerivativeFunc::FUNC_Y, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true));
+ add_options.push_back(AddOption("DdYS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Derivative in 'y' using local differencing."), VisualShaderNodeScalarDerivativeFunc::FUNC_Y, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true));
+ add_options.push_back(AddOption("Sum", "Special", "Derivative", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and 'y'."), VisualShaderNodeVectorDerivativeFunc::FUNC_SUM, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true));
+ add_options.push_back(AddOption("SumS", "Special", "Derivative", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) (Scalar) Sum of absolute derivative in 'x' and 'y'."), VisualShaderNodeScalarDerivativeFunc::FUNC_SUM, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT, -1, -1, true));
custom_node_option_idx = add_options.size();
/////////////////////////////////////////////////////////////////////
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index 9b80488b22..ff2b0dc6ab 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -85,6 +85,14 @@ class VisualShaderEditor : public VBoxContainer {
bool preview_showed;
+ enum TypeFlags {
+ TYPE_FLAGS_VERTEX = 1,
+ TYPE_FLAGS_FRAGMENT = 2,
+ TYPE_FLAGS_LIGHT = 4,
+ TYPE_FLAGS_COMPUTE = 8,
+ TYPE_FLAGS_VERTEX_FRAGMENT_LIGHT = TYPE_FLAGS_VERTEX | TYPE_FLAGS_FRAGMENT | TYPE_FLAGS_LIGHT,
+ };
+
enum ToolsMenuOptions {
EXPAND_ALL,
COLLAPSE_ALL
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 35311b32eb..ea55029de0 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -330,6 +330,7 @@ private:
return;
}
}
+
String sp = p.simplify_path();
project_path->set_text(sp);
_path_text_changed(sp);
@@ -411,7 +412,7 @@ private:
_test_path();
if (p_text == "") {
- set_message(TTR("It would be a good idea to name your project."), MESSAGE_WARNING);
+ set_message(TTR("It would be a good idea to name your project."), MESSAGE_ERROR);
}
}
@@ -1012,7 +1013,7 @@ public:
void update_dock_menu();
void load_projects();
void set_search_term(String p_search_term);
- void set_order_option(ProjectListFilter::FilterOption p_option);
+ void set_order_option(int p_option);
void sort_projects();
int get_project_count() const;
void select_project(int p_index);
@@ -1045,7 +1046,7 @@ private:
static void load_project_data(const String &p_property_key, Item &p_item, bool p_favorite);
String _search_term;
- ProjectListFilter::FilterOption _order_option;
+ FilterOption _order_option;
Set<String> _selected_project_keys;
String _last_clicked; // Project key
VBoxContainer *_scroll_children;
@@ -1055,7 +1056,7 @@ private:
};
struct ProjectListComparator {
- ProjectListFilter::FilterOption order_option;
+ FilterOption order_option;
// operator<
_FORCE_INLINE_ bool operator()(const ProjectList::Item &a, const ProjectList::Item &b) const {
@@ -1066,9 +1067,9 @@ struct ProjectListComparator {
return false;
}
switch (order_option) {
- case ProjectListFilter::FILTER_PATH:
+ case PATH:
return a.project_key < b.project_key;
- case ProjectListFilter::FILTER_EDIT_DATE:
+ case EDIT_DATE:
return a.last_edited > b.last_edited;
default:
return a.project_name < b.project_name;
@@ -1077,8 +1078,7 @@ struct ProjectListComparator {
};
ProjectList::ProjectList() {
- _order_option = ProjectListFilter::FILTER_EDIT_DATE;
-
+ _order_option = FilterOption::NAME;
_scroll_children = memnew(VBoxContainer);
_scroll_children->set_h_size_flags(Control::SIZE_EXPAND_FILL);
add_child(_scroll_children);
@@ -1238,8 +1238,6 @@ void ProjectList::load_projects() {
create_project_item_control(i);
}
- sort_projects();
-
set_v_scroll(0);
update_icons_async();
@@ -1391,12 +1389,13 @@ void ProjectList::set_search_term(String p_search_term) {
_search_term = p_search_term;
}
-void ProjectList::set_order_option(ProjectListFilter::FilterOption p_option) {
- if (_order_option != p_option) {
- _order_option = p_option;
- EditorSettings::get_singleton()->set("project_manager/sorting_order", (int)_order_option);
- EditorSettings::get_singleton()->save();
- }
+void ProjectList::set_order_option(int p_option) {
+ FilterOption selected = (FilterOption)p_option;
+ EditorSettings::get_singleton()->set("project_manager/sorting_order", p_option);
+ EditorSettings::get_singleton()->save();
+ _order_option = selected;
+
+ sort_projects();
}
void ProjectList::sort_projects() {
@@ -1798,6 +1797,9 @@ void ProjectList::_bind_methods() {
void ProjectManager::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
+ search_box->set_right_icon(get_theme_icon("Search", "EditorIcons"));
+ search_box->set_clear_button_enabled(true);
+
Engine::get_singleton()->set_editor_hint(false);
} break;
case NOTIFICATION_RESIZED: {
@@ -1806,6 +1808,10 @@ void ProjectManager::_notification(int p_what) {
}
} break;
case NOTIFICATION_READY: {
+ int default_sorting = (int)EditorSettings::get_singleton()->get("project_manager/sorting_order");
+ filter_option->select(default_sorting);
+ _project_list->set_order_option(default_sorting);
+
if (_project_list->get_project_count() == 0 && StreamPeerSSL::is_available()) {
open_templates->popup_centered();
}
@@ -1813,7 +1819,7 @@ void ProjectManager::_notification(int p_what) {
if (_project_list->get_project_count() >= 1) {
// Focus on the search box immediately to allow the user
// to search without having to reach for their mouse
- project_filter->search_box->grab_focus();
+ search_box->grab_focus();
}
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -1833,7 +1839,7 @@ void ProjectManager::_dim_window() {
// No transition is applied, as the effect needs to be visible immediately
float c = 0.5f;
Color dim_color = Color(c, c, c);
- gui_base->set_modulate(dim_color);
+ set_modulate(dim_color);
}
void ProjectManager::_update_project_buttons() {
@@ -1853,7 +1859,7 @@ void ProjectManager::_update_project_buttons() {
rename_btn->set_disabled(empty_selection || is_missing_project_selected);
run_btn->set_disabled(empty_selection || is_missing_project_selected);
- erase_missing_btn->set_visible(_project_list->is_any_project_missing());
+ erase_missing_btn->set_disabled(!_project_list->is_any_project_missing());
}
void ProjectManager::_unhandled_input(const Ref<InputEvent> &p_ev) {
@@ -1930,7 +1936,7 @@ void ProjectManager::_unhandled_input(const Ref<InputEvent> &p_ev) {
} break;
case KEY_F: {
if (k->get_command()) {
- this->project_filter->search_box->grab_focus();
+ this->search_box->grab_focus();
} else {
keycode_handled = false;
}
@@ -1947,8 +1953,7 @@ void ProjectManager::_unhandled_input(const Ref<InputEvent> &p_ev) {
}
void ProjectManager::_load_recent_projects() {
- _project_list->set_order_option(project_order_filter->get_filter_option());
- _project_list->set_search_term(project_filter->get_search_term());
+ _project_list->set_search_term(search_box->get_text().strip_edges());
_project_list->load_projects();
_update_project_buttons();
@@ -1970,7 +1975,7 @@ void ProjectManager::_on_projects_updated() {
}
void ProjectManager::_on_project_created(const String &dir) {
- project_filter->clear();
+ search_box->clear();
int i = _project_list->refresh_project(dir);
_project_list->select_project(i);
_project_list->ensure_project_visible(i);
@@ -2113,7 +2118,6 @@ void ProjectManager::_run_project_confirm() {
}
}
-// When you press the "Run" button
void ProjectManager::_run_project() {
const Set<String> &selected_list = _project_list->get_selected_project_keys();
@@ -2226,8 +2230,6 @@ void ProjectManager::_erase_missing_projects() {
void ProjectManager::_language_selected(int p_id) {
String lang = language_btn->get_item_metadata(p_id);
EditorSettings::get_singleton()->set("interface/editor/editor_language", lang);
- language_btn->set_text(lang);
- language_btn->set_icon(get_theme_icon("Environment", "EditorIcons"));
language_restart_ask->set_text(TTR("Language changed.\nThe interface will update after restarting the editor or project manager."));
language_restart_ask->popup_centered();
@@ -2304,13 +2306,14 @@ void ProjectManager::_scan_multiple_folders(PackedStringArray p_files) {
}
}
-void ProjectManager::_on_order_option_changed() {
- _project_list->set_order_option(project_order_filter->get_filter_option());
- _project_list->sort_projects();
+void ProjectManager::_on_order_option_changed(int p_idx) {
+ if (is_inside_tree()) {
+ _project_list->set_order_option(p_idx);
+ }
}
-void ProjectManager::_on_filter_option_changed() {
- _project_list->set_search_term(project_filter->get_search_term());
+void ProjectManager::_on_search_term_changed(const String &p_term) {
+ _project_list->set_search_term(p_term);
_project_list->sort_projects();
// Select the first visible project in the list.
@@ -2341,7 +2344,6 @@ ProjectManager::ProjectManager() {
{
int display_scale = EditorSettings::get_singleton()->get("interface/editor/display_scale");
- float custom_display_scale = EditorSettings::get_singleton()->get("interface/editor/custom_display_scale");
switch (display_scale) {
case 0: {
@@ -2372,9 +2374,8 @@ ProjectManager::ProjectManager() {
case 6:
editor_set_scale(2.0);
break;
-
default: {
- editor_set_scale(custom_display_scale);
+ editor_set_scale(EditorSettings::get_singleton()->get("interface/editor/custom_display_scale"));
} break;
}
@@ -2385,28 +2386,26 @@ ProjectManager::ProjectManager() {
DisplayServer::get_singleton()->window_set_size(DisplayServer::get_singleton()->window_get_size() * MAX(1, EDSCALE));
}
+ String cp;
+ cp += 0xA9;
+ DisplayServer::get_singleton()->window_set_title(VERSION_NAME + String(" - ") + TTR("Project Manager") + " - " + cp + " 2007-2020 Juan Linietsky, Ariel Manzur & Godot Contributors");
+
FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files"));
set_anchors_and_margins_preset(Control::PRESET_WIDE);
set_theme(create_custom_theme());
- gui_base = memnew(Control);
- add_child(gui_base);
- gui_base->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ set_anchors_and_margins_preset(Control::PRESET_WIDE);
Panel *panel = memnew(Panel);
- gui_base->add_child(panel);
+ add_child(panel);
panel->set_anchors_and_margins_preset(Control::PRESET_WIDE);
- panel->add_theme_style_override("panel", gui_base->get_theme_stylebox("Background", "EditorStyles"));
+ panel->add_theme_style_override("panel", get_theme_stylebox("Background", "EditorStyles"));
VBoxContainer *vb = memnew(VBoxContainer);
panel->add_child(vb);
vb->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 8 * EDSCALE);
- String cp;
- cp += 0xA9;
- DisplayServer::get_singleton()->window_set_title(VERSION_NAME + String(" - ") + TTR("Project Manager") + " - " + cp + " 2007-2020 Juan Linietsky, Ariel Manzur & Godot Contributors");
-
Control *center_box = memnew(Control);
center_box->set_v_size_flags(Control::SIZE_EXPAND_FILL);
vb->add_child(center_box);
@@ -2416,218 +2415,231 @@ ProjectManager::ProjectManager() {
tabs->set_anchors_and_margins_preset(Control::PRESET_WIDE);
tabs->set_tab_align(TabContainer::ALIGN_LEFT);
- HBoxContainer *tree_hb = memnew(HBoxContainer);
- projects_hb = tree_hb;
-
+ HBoxContainer *projects_hb = memnew(HBoxContainer);
projects_hb->set_name(TTR("Projects"));
+ tabs->add_child(projects_hb);
- tabs->add_child(tree_hb);
-
- VBoxContainer *search_tree_vb = memnew(VBoxContainer);
- tree_hb->add_child(search_tree_vb);
- search_tree_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
-
- HBoxContainer *sort_filters = memnew(HBoxContainer);
- Label *sort_label = memnew(Label);
- sort_label->set_text(TTR("Sort:"));
- sort_filters->add_child(sort_label);
- Vector<String> sort_filter_titles;
- sort_filter_titles.push_back(TTR("Name"));
- sort_filter_titles.push_back(TTR("Path"));
- sort_filter_titles.push_back(TTR("Last Edited"));
- project_order_filter = memnew(ProjectListFilter);
- project_order_filter->add_filter_option();
- project_order_filter->_setup_filters(sort_filter_titles);
- project_order_filter->set_filter_size(150);
- sort_filters->add_child(project_order_filter);
- project_order_filter->connect("filter_changed", callable_mp(this, &ProjectManager::_on_order_option_changed));
- project_order_filter->set_custom_minimum_size(Size2(180, 10) * EDSCALE);
-
- int projects_sorting_order = (int)EditorSettings::get_singleton()->get("project_manager/sorting_order");
- project_order_filter->set_filter_option((ProjectListFilter::FilterOption)projects_sorting_order);
-
- sort_filters->add_spacer(true);
-
- project_filter = memnew(ProjectListFilter);
- project_filter->add_search_box();
- project_filter->connect("filter_changed", callable_mp(this, &ProjectManager::_on_filter_option_changed));
- project_filter->set_custom_minimum_size(Size2(280, 10) * EDSCALE);
- sort_filters->add_child(project_filter);
-
- search_tree_vb->add_child(sort_filters);
-
- PanelContainer *pc = memnew(PanelContainer);
- pc->add_theme_style_override("panel", gui_base->get_theme_stylebox("bg", "Tree"));
- search_tree_vb->add_child(pc);
- pc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
-
- _project_list = memnew(ProjectList);
- _project_list->connect(ProjectList::SIGNAL_SELECTION_CHANGED, callable_mp(this, &ProjectManager::_update_project_buttons));
- _project_list->connect(ProjectList::SIGNAL_PROJECT_ASK_OPEN, callable_mp(this, &ProjectManager::_open_selected_projects_ask));
- pc->add_child(_project_list);
- _project_list->set_enable_h_scroll(false);
-
- VBoxContainer *tree_vb = memnew(VBoxContainer);
- tree_hb->add_child(tree_vb);
-
- Button *open = memnew(Button);
- open->set_text(TTR("Edit"));
- tree_vb->add_child(open);
- open->connect("pressed", callable_mp(this, &ProjectManager::_open_selected_projects_ask));
- open_btn = open;
-
- Button *run = memnew(Button);
- run->set_text(TTR("Run"));
- tree_vb->add_child(run);
- run->connect("pressed", callable_mp(this, &ProjectManager::_run_project));
- run_btn = run;
-
- tree_vb->add_child(memnew(HSeparator));
-
- Button *scan = memnew(Button);
- scan->set_text(TTR("Scan"));
- tree_vb->add_child(scan);
- scan->connect("pressed", callable_mp(this, &ProjectManager::_scan_projects));
-
- tree_vb->add_child(memnew(HSeparator));
-
- scan_dir = memnew(FileDialog);
- scan_dir->set_access(FileDialog::ACCESS_FILESYSTEM);
- scan_dir->set_file_mode(FileDialog::FILE_MODE_OPEN_DIR);
- scan_dir->set_title(TTR("Select a Folder to Scan")); // must be after mode or it's overridden
- scan_dir->set_current_dir(EditorSettings::get_singleton()->get("filesystem/directories/default_project_path"));
- gui_base->add_child(scan_dir);
- scan_dir->connect("dir_selected", callable_mp(this, &ProjectManager::_scan_begin));
-
- Button *create = memnew(Button);
- create->set_text(TTR("New Project"));
- tree_vb->add_child(create);
- create->connect("pressed", callable_mp(this, &ProjectManager::_new_project));
-
- Button *import = memnew(Button);
- import->set_text(TTR("Import"));
- tree_vb->add_child(import);
- import->connect("pressed", callable_mp(this, &ProjectManager::_import_project));
-
- Button *rename = memnew(Button);
- rename->set_text(TTR("Rename"));
- tree_vb->add_child(rename);
- rename->connect("pressed", callable_mp(this, &ProjectManager::_rename_project));
- rename_btn = rename;
-
- Button *erase = memnew(Button);
- erase->set_text(TTR("Remove"));
- tree_vb->add_child(erase);
- erase->connect("pressed", callable_mp(this, &ProjectManager::_erase_project));
- erase_btn = erase;
-
- Button *erase_missing = memnew(Button);
- erase_missing->set_text(TTR("Remove Missing"));
- tree_vb->add_child(erase_missing);
- erase_missing->connect("pressed", callable_mp(this, &ProjectManager::_erase_missing_projects));
- erase_missing_btn = erase_missing;
-
- tree_vb->add_spacer();
+ {
+ // Projects + search bar
+ VBoxContainer *search_tree_vb = memnew(VBoxContainer);
+ projects_hb->add_child(search_tree_vb);
+ search_tree_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- if (StreamPeerSSL::is_available()) {
- asset_library = memnew(EditorAssetLibrary(true));
- asset_library->set_name(TTR("Templates"));
- tabs->add_child(asset_library);
- asset_library->connect("install_asset", callable_mp(this, &ProjectManager::_install_project));
- } else {
- WARN_PRINT("Asset Library not available, as it requires SSL to work.");
- }
+ HBoxContainer *hb = memnew(HBoxContainer);
+ hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ search_tree_vb->add_child(hb);
- HBoxContainer *settings_hb = memnew(HBoxContainer);
- settings_hb->set_alignment(BoxContainer::ALIGN_END);
- settings_hb->set_h_grow_direction(Control::GROW_DIRECTION_BEGIN);
+ search_box = memnew(LineEdit);
+ search_box->set_placeholder(TTR("Search"));
+ search_box->set_tooltip(TTR("The search box filters projects by name and last path component.\nTo filter projects by name and full path, the query must contain at least one `/` character."));
+ search_box->connect("text_changed", callable_mp(this, &ProjectManager::_on_search_term_changed));
+ search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ hb->add_child(search_box);
- Label *version_label = memnew(Label);
- String hash = String(VERSION_HASH);
- if (hash.length() != 0) {
- hash = "." + hash.left(9);
- }
- version_label->set_text("v" VERSION_FULL_BUILD "" + hash);
- // Fade out the version label to be less prominent, but still readable
- version_label->set_self_modulate(Color(1, 1, 1, 0.6));
- version_label->set_align(Label::ALIGN_CENTER);
- settings_hb->add_child(version_label);
+ hb->add_spacer();
- language_btn = memnew(OptionButton);
- language_btn->set_flat(true);
- language_btn->set_focus_mode(Control::FOCUS_NONE);
+ Label *sort_label = memnew(Label);
+ sort_label->set_text(TTR("Sort:"));
+ hb->add_child(sort_label);
- Vector<String> editor_languages;
- List<PropertyInfo> editor_settings_properties;
- EditorSettings::get_singleton()->get_property_list(&editor_settings_properties);
- for (List<PropertyInfo>::Element *E = editor_settings_properties.front(); E; E = E->next()) {
- PropertyInfo &pi = E->get();
- if (pi.name == "interface/editor/editor_language") {
- editor_languages = pi.hint_string.split(",");
- }
- }
- String current_lang = EditorSettings::get_singleton()->get("interface/editor/editor_language");
- for (int i = 0; i < editor_languages.size(); i++) {
- String lang = editor_languages[i];
- String lang_name = TranslationServer::get_singleton()->get_locale_name(lang);
- language_btn->add_item(lang_name + " [" + lang + "]", i);
- language_btn->set_item_metadata(i, lang);
- if (current_lang == lang) {
- language_btn->select(i);
- language_btn->set_text(lang);
- }
- }
- language_btn->set_icon(get_theme_icon("Environment", "EditorIcons"));
+ filter_option = memnew(OptionButton);
+ filter_option->set_clip_text(true);
+ filter_option->set_custom_minimum_size(Size2(150 * EDSCALE, 10 * EDSCALE));
+ filter_option->connect("item_selected", callable_mp(this, &ProjectManager::_on_order_option_changed));
+ hb->add_child(filter_option);
- settings_hb->add_child(language_btn);
- language_btn->connect("item_selected", callable_mp(this, &ProjectManager::_language_selected));
+ Vector<String> sort_filter_titles;
+ sort_filter_titles.push_back(TTR("Name"));
+ sort_filter_titles.push_back(TTR("Path"));
+ sort_filter_titles.push_back(TTR("Last Edited"));
- center_box->add_child(settings_hb);
- settings_hb->set_anchors_and_margins_preset(Control::PRESET_TOP_RIGHT);
+ for (int i = 0; i < sort_filter_titles.size(); i++) {
+ filter_option->add_item(sort_filter_titles[i]);
+ }
- //////////////////////////////////////////////////////////////
+ PanelContainer *pc = memnew(PanelContainer);
+ pc->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree"));
+ pc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ search_tree_vb->add_child(pc);
- language_restart_ask = memnew(ConfirmationDialog);
- language_restart_ask->get_ok()->set_text(TTR("Restart Now"));
- language_restart_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_restart_confirm));
- language_restart_ask->get_cancel()->set_text(TTR("Continue"));
- gui_base->add_child(language_restart_ask);
+ _project_list = memnew(ProjectList);
+ _project_list->connect(ProjectList::SIGNAL_SELECTION_CHANGED, callable_mp(this, &ProjectManager::_update_project_buttons));
+ _project_list->connect(ProjectList::SIGNAL_PROJECT_ASK_OPEN, callable_mp(this, &ProjectManager::_open_selected_projects_ask));
+ _project_list->set_enable_h_scroll(false);
+ pc->add_child(_project_list);
+ }
- erase_missing_ask = memnew(ConfirmationDialog);
- erase_missing_ask->get_ok()->set_text(TTR("Remove All"));
- erase_missing_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_erase_missing_projects_confirm));
- gui_base->add_child(erase_missing_ask);
+ {
+ // Project tab side bar
+ VBoxContainer *tree_vb = memnew(VBoxContainer);
+ tree_vb->set_custom_minimum_size(Size2(120, 120));
+ projects_hb->add_child(tree_vb);
+
+ Button *create = memnew(Button);
+ create->set_text(TTR("New Project"));
+ create->connect("pressed", callable_mp(this, &ProjectManager::_new_project));
+ tree_vb->add_child(create);
+
+ Button *import = memnew(Button);
+ import->set_text(TTR("Import"));
+ import->connect("pressed", callable_mp(this, &ProjectManager::_import_project));
+ tree_vb->add_child(import);
+
+ Button *scan = memnew(Button);
+ scan->set_text(TTR("Scan"));
+ scan->connect("pressed", callable_mp(this, &ProjectManager::_scan_projects));
+ tree_vb->add_child(scan);
+
+ tree_vb->add_child(memnew(HSeparator));
+
+ open_btn = memnew(Button);
+ open_btn->set_text(TTR("Edit"));
+ open_btn->connect("pressed", callable_mp(this, &ProjectManager::_open_selected_projects_ask));
+ tree_vb->add_child(open_btn);
+
+ run_btn = memnew(Button);
+ run_btn->set_text(TTR("Run"));
+ run_btn->connect("pressed", callable_mp(this, &ProjectManager::_run_project));
+ tree_vb->add_child(run_btn);
+
+ rename_btn = memnew(Button);
+ rename_btn->set_text(TTR("Rename"));
+ rename_btn->connect("pressed", callable_mp(this, &ProjectManager::_rename_project));
+ tree_vb->add_child(rename_btn);
+
+ erase_btn = memnew(Button);
+ erase_btn->set_text(TTR("Remove"));
+ erase_btn->connect("pressed", callable_mp(this, &ProjectManager::_erase_project));
+ tree_vb->add_child(erase_btn);
+
+ erase_missing_btn = memnew(Button);
+ erase_missing_btn->set_text(TTR("Remove Missing"));
+ erase_missing_btn->connect("pressed", callable_mp(this, &ProjectManager::_erase_missing_projects));
+ tree_vb->add_child(erase_missing_btn);
+ }
- erase_ask = memnew(ConfirmationDialog);
- erase_ask->get_ok()->set_text(TTR("Remove"));
- erase_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_erase_project_confirm));
- gui_base->add_child(erase_ask);
+ {
+ // Version info and language options
+ HBoxContainer *settings_hb = memnew(HBoxContainer);
+ settings_hb->set_alignment(BoxContainer::ALIGN_END);
+ settings_hb->set_h_grow_direction(Control::GROW_DIRECTION_BEGIN);
+
+ Label *version_label = memnew(Label);
+ String hash = String(VERSION_HASH);
+ if (hash.length() != 0) {
+ hash = "." + hash.left(9);
+ }
+ version_label->set_text("v" VERSION_FULL_BUILD "" + hash);
+ version_label->set_self_modulate(Color(1, 1, 1, 0.6));
+ version_label->set_align(Label::ALIGN_CENTER);
+ settings_hb->add_child(version_label);
+
+ language_btn = memnew(OptionButton);
+ language_btn->set_flat(true);
+ language_btn->set_icon(get_theme_icon("Environment", "EditorIcons"));
+ language_btn->set_focus_mode(Control::FOCUS_NONE);
+ language_btn->connect("item_selected", callable_mp(this, &ProjectManager::_language_selected));
+
+ Vector<String> editor_languages;
+ List<PropertyInfo> editor_settings_properties;
+ EditorSettings::get_singleton()->get_property_list(&editor_settings_properties);
+ for (List<PropertyInfo>::Element *E = editor_settings_properties.front(); E; E = E->next()) {
+ PropertyInfo &pi = E->get();
+ if (pi.name == "interface/editor/editor_language") {
+ editor_languages = pi.hint_string.split(",");
+ break;
+ }
+ }
- multi_open_ask = memnew(ConfirmationDialog);
- multi_open_ask->get_ok()->set_text(TTR("Edit"));
- multi_open_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_open_selected_projects));
- gui_base->add_child(multi_open_ask);
+ String current_lang = EditorSettings::get_singleton()->get("interface/editor/editor_language");
+ language_btn->set_text(current_lang);
- multi_run_ask = memnew(ConfirmationDialog);
- multi_run_ask->get_ok()->set_text(TTR("Run"));
- multi_run_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_run_project_confirm));
- gui_base->add_child(multi_run_ask);
+ for (int i = 0; i < editor_languages.size(); i++) {
+ String lang = editor_languages[i];
+ String lang_name = TranslationServer::get_singleton()->get_locale_name(lang);
+ language_btn->add_item(lang_name + " [" + lang + "]", i);
+ language_btn->set_item_metadata(i, lang);
+ if (current_lang == lang) {
+ language_btn->select(i);
+ }
+ }
- multi_scan_ask = memnew(ConfirmationDialog);
- multi_scan_ask->get_ok()->set_text(TTR("Scan"));
- gui_base->add_child(multi_scan_ask);
+ settings_hb->add_child(language_btn);
+ center_box->add_child(settings_hb);
+ settings_hb->set_anchors_and_margins_preset(Control::PRESET_TOP_RIGHT);
+ }
- ask_update_settings = memnew(ConfirmationDialog);
- ask_update_settings->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_confirm_update_settings));
- gui_base->add_child(ask_update_settings);
+ if (StreamPeerSSL::is_available()) {
+ asset_library = memnew(EditorAssetLibrary(true));
+ asset_library->set_name(TTR("Templates"));
+ tabs->add_child(asset_library);
+ asset_library->connect("install_asset", callable_mp(this, &ProjectManager::_install_project));
+ } else {
+ WARN_PRINT("Asset Library not available, as it requires SSL to work.");
+ }
- OS::get_singleton()->set_low_processor_usage_mode(true);
+ {
+ // Dialogs
+ language_restart_ask = memnew(ConfirmationDialog);
+ language_restart_ask->get_ok()->set_text(TTR("Restart Now"));
+ language_restart_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_restart_confirm));
+ language_restart_ask->get_cancel()->set_text(TTR("Continue"));
+ add_child(language_restart_ask);
+
+ scan_dir = memnew(FileDialog);
+ scan_dir->set_access(FileDialog::ACCESS_FILESYSTEM);
+ scan_dir->set_file_mode(FileDialog::FILE_MODE_OPEN_DIR);
+ scan_dir->set_title(TTR("Select a Folder to Scan")); // must be after mode or it's overridden
+ scan_dir->set_current_dir(EditorSettings::get_singleton()->get("filesystem/directories/default_project_path"));
+ add_child(scan_dir);
+ scan_dir->connect("dir_selected", callable_mp(this, &ProjectManager::_scan_begin));
+
+ erase_missing_ask = memnew(ConfirmationDialog);
+ erase_missing_ask->get_ok()->set_text(TTR("Remove All"));
+ erase_missing_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_erase_missing_projects_confirm));
+ add_child(erase_missing_ask);
+
+ erase_ask = memnew(ConfirmationDialog);
+ erase_ask->get_ok()->set_text(TTR("Remove"));
+ erase_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_erase_project_confirm));
+ add_child(erase_ask);
+
+ multi_open_ask = memnew(ConfirmationDialog);
+ multi_open_ask->get_ok()->set_text(TTR("Edit"));
+ multi_open_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_open_selected_projects));
+ add_child(multi_open_ask);
+
+ multi_run_ask = memnew(ConfirmationDialog);
+ multi_run_ask->get_ok()->set_text(TTR("Run"));
+ multi_run_ask->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_run_project_confirm));
+ add_child(multi_run_ask);
+
+ multi_scan_ask = memnew(ConfirmationDialog);
+ multi_scan_ask->get_ok()->set_text(TTR("Scan"));
+ add_child(multi_scan_ask);
+
+ ask_update_settings = memnew(ConfirmationDialog);
+ ask_update_settings->get_ok()->connect("pressed", callable_mp(this, &ProjectManager::_confirm_update_settings));
+ add_child(ask_update_settings);
+
+ npdialog = memnew(ProjectDialog);
+ npdialog->connect("projects_updated", callable_mp(this, &ProjectManager::_on_projects_updated));
+ npdialog->connect("project_created", callable_mp(this, &ProjectManager::_on_project_created));
+ add_child(npdialog);
+
+ run_error_diag = memnew(AcceptDialog);
+ run_error_diag->set_title(TTR("Can't run project"));
+ add_child(run_error_diag);
- npdialog = memnew(ProjectDialog);
- gui_base->add_child(npdialog);
+ dialog_error = memnew(AcceptDialog);
+ add_child(dialog_error);
- npdialog->connect("projects_updated", callable_mp(this, &ProjectManager::_on_projects_updated));
- npdialog->connect("project_created", callable_mp(this, &ProjectManager::_on_project_created));
+ open_templates = memnew(ConfirmationDialog);
+ open_templates->set_text(TTR("You currently don't have any projects.\nWould you like to explore official example projects in the Asset Library?"));
+ open_templates->get_ok()->set_text(TTR("Open Asset Library"));
+ open_templates->connect("confirmed", callable_mp(this, &ProjectManager::_open_asset_library));
+ add_child(open_templates);
+ }
_load_recent_projects();
@@ -2637,18 +2649,7 @@ ProjectManager::ProjectManager() {
SceneTree::get_singleton()->get_root()->connect("files_dropped", callable_mp(this, &ProjectManager::_files_dropped));
- run_error_diag = memnew(AcceptDialog);
- gui_base->add_child(run_error_diag);
- run_error_diag->set_title(TTR("Can't run project"));
-
- dialog_error = memnew(AcceptDialog);
- gui_base->add_child(dialog_error);
-
- open_templates = memnew(ConfirmationDialog);
- open_templates->set_text(TTR("You currently don't have any projects.\nWould you like to explore official example projects in the Asset Library?"));
- open_templates->get_ok()->set_text(TTR("Open Asset Library"));
- open_templates->connect("confirmed", callable_mp(this, &ProjectManager::_open_asset_library));
- add_child(open_templates);
+ OS::get_singleton()->set_low_processor_usage_mode(true);
}
ProjectManager::~ProjectManager() {
@@ -2656,82 +2657,3 @@ ProjectManager::~ProjectManager() {
EditorSettings::destroy();
}
}
-
-void ProjectListFilter::_setup_filters(Vector<String> options) {
- filter_option->clear();
- for (int i = 0; i < options.size(); i++) {
- filter_option->add_item(options[i]);
- }
-}
-
-void ProjectListFilter::_search_text_changed(const String &p_newtext) {
- emit_signal("filter_changed");
-}
-
-String ProjectListFilter::get_search_term() {
- return search_box->get_text().strip_edges();
-}
-
-ProjectListFilter::FilterOption ProjectListFilter::get_filter_option() {
- return _current_filter;
-}
-
-void ProjectListFilter::set_filter_option(FilterOption option) {
- filter_option->select((int)option);
- _filter_option_selected(0);
-}
-
-void ProjectListFilter::_filter_option_selected(int p_idx) {
- FilterOption selected = (FilterOption)(filter_option->get_selected());
- if (_current_filter != selected) {
- _current_filter = selected;
- if (is_inside_tree()) {
- emit_signal("filter_changed");
- }
- }
-}
-
-void ProjectListFilter::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE && has_search_box) {
- search_box->set_right_icon(get_theme_icon("Search", "EditorIcons"));
- search_box->set_clear_button_enabled(true);
- }
-}
-
-void ProjectListFilter::_bind_methods() {
- ADD_SIGNAL(MethodInfo("filter_changed"));
-}
-
-void ProjectListFilter::add_filter_option() {
- filter_option = memnew(OptionButton);
- filter_option->set_clip_text(true);
- filter_option->connect("item_selected", callable_mp(this, &ProjectListFilter::_filter_option_selected));
- add_child(filter_option);
-}
-
-void ProjectListFilter::add_search_box() {
- search_box = memnew(LineEdit);
- search_box->set_placeholder(TTR("Search"));
- search_box->set_tooltip(
- TTR("The search box filters projects by name and last path component.\nTo filter projects by name and full path, the query must contain at least one `/` character."));
- search_box->connect("text_changed", callable_mp(this, &ProjectListFilter::_search_text_changed));
- search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- add_child(search_box);
-
- has_search_box = true;
-}
-
-void ProjectListFilter::set_filter_size(int h_size) {
- filter_option->set_custom_minimum_size(Size2(h_size * EDSCALE, 10 * EDSCALE));
-}
-
-ProjectListFilter::ProjectListFilter() {
- _current_filter = FILTER_NAME;
- has_search_box = false;
-}
-
-void ProjectListFilter::clear() {
- if (has_search_box) {
- search_box->clear();
- }
-}
diff --git a/editor/project_manager.h b/editor/project_manager.h
index 66b38d0746..407dba0c94 100644
--- a/editor/project_manager.h
+++ b/editor/project_manager.h
@@ -39,22 +39,31 @@
class ProjectDialog;
class ProjectList;
-class ProjectListFilter;
+
+enum FilterOption {
+ NAME,
+ PATH,
+ EDIT_DATE,
+};
class ProjectManager : public Control {
GDCLASS(ProjectManager, Control);
- Button *erase_btn;
- Button *erase_missing_btn;
+ TabContainer *tabs;
+
+ ProjectList *_project_list;
+
+ LineEdit *search_box;
+ OptionButton *filter_option;
+
+ Button *run_btn;
Button *open_btn;
Button *rename_btn;
- Button *run_btn;
+ Button *erase_btn;
+ Button *erase_missing_btn;
EditorAssetLibrary *asset_library;
- ProjectListFilter *project_filter;
- ProjectListFilter *project_order_filter;
-
FileDialog *scan_dir;
ConfirmationDialog *language_restart_ask;
ConfirmationDialog *erase_ask;
@@ -64,18 +73,12 @@ class ProjectManager : public Control {
ConfirmationDialog *multi_scan_ask;
ConfirmationDialog *ask_update_settings;
ConfirmationDialog *open_templates;
+
AcceptDialog *run_error_diag;
AcceptDialog *dialog_error;
ProjectDialog *npdialog;
- HBoxContainer *projects_hb;
- TabContainer *tabs;
- ProjectList *_project_list;
-
OptionButton *language_btn;
- Control *gui_base;
-
- bool importing;
void _open_asset_library();
void _scan_projects();
@@ -94,14 +97,13 @@ class ProjectManager : public Control {
void _language_selected(int p_id);
void _restart_confirm();
void _exit_dialog();
- void _scan_begin(const String &p_base);
-
void _confirm_update_settings();
void _load_recent_projects();
void _on_project_created(const String &dir);
void _on_projects_updated();
- void _update_scroll_position(const String &dir);
+ void _scan_multiple_folders(PackedStringArray p_files);
+ void _scan_begin(const String &p_base);
void _scan_dir(const String &path, List<String> *r_projects);
void _install_project(const String &p_zip_path, const String &p_title);
@@ -109,10 +111,9 @@ class ProjectManager : public Control {
void _dim_window();
void _unhandled_input(const Ref<InputEvent> &p_ev);
void _files_dropped(PackedStringArray p_files, int p_screen);
- void _scan_multiple_folders(PackedStringArray p_files);
- void _on_order_option_changed();
- void _on_filter_option_changed();
+ void _on_order_option_changed(int p_idx);
+ void _on_search_term_changed(const String &p_term);
protected:
void _notification(int p_what);
@@ -123,41 +124,4 @@ public:
~ProjectManager();
};
-class ProjectListFilter : public HBoxContainer {
- GDCLASS(ProjectListFilter, HBoxContainer);
-
-public:
- enum FilterOption {
- FILTER_NAME,
- FILTER_PATH,
- FILTER_EDIT_DATE,
- };
-
-private:
- friend class ProjectManager;
-
- OptionButton *filter_option;
- LineEdit *search_box;
- bool has_search_box;
- FilterOption _current_filter;
-
- void _search_text_changed(const String &p_newtext);
- void _filter_option_selected(int p_idx);
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void _setup_filters(Vector<String> options);
- void add_filter_option();
- void add_search_box();
- void set_filter_size(int h_size);
- String get_search_term();
- FilterOption get_filter_option();
- void set_filter_option(FilterOption);
- ProjectListFilter();
- void clear();
-};
-
#endif // PROJECT_MANAGER_H
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 82ac225ddb..b6621d0d1e 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -333,6 +333,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
header->add_child(search_bar);
search_box = memnew(LineEdit);
+ search_box->set_placeholder(TTR("Search"));
search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
search_bar->add_child(search_box);
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index 628475bbc0..90efb11b7d 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -722,6 +722,15 @@ void ScriptCreateDialog::_update_dialog() {
}
get_ok()->set_disabled(!script_ok);
+
+ Callable entered_call = callable_mp(this, &ScriptCreateDialog::_path_entered);
+ if (script_ok) {
+ if (!file_path->is_connected("text_entered", entered_call)) {
+ file_path->connect("text_entered", entered_call);
+ }
+ } else if (file_path->is_connected("text_entered", entered_call)) {
+ file_path->disconnect("text_entered", entered_call);
+ }
}
void ScriptCreateDialog::_bind_methods() {
@@ -849,7 +858,6 @@ ScriptCreateDialog::ScriptCreateDialog() {
hb->connect("sort_children", callable_mp(this, &ScriptCreateDialog::_path_hbox_sorted));
file_path = memnew(LineEdit);
file_path->connect("text_changed", callable_mp(this, &ScriptCreateDialog::_path_changed));
- file_path->connect("text_entered", callable_mp(this, &ScriptCreateDialog::_path_entered));
file_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hb->add_child(file_path);
path_button = memnew(Button);
diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp
index 9f286bd8f6..35610ef71b 100644
--- a/editor/settings_config_dialog.cpp
+++ b/editor/settings_config_dialog.cpp
@@ -405,6 +405,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
tab_general->add_child(hbc);
search_box = memnew(LineEdit);
+ search_box->set_placeholder(TTR("Search"));
search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hbc->add_child(search_box);
@@ -449,6 +450,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
tab_shortcuts->add_child(hbc);
shortcut_search_box = memnew(LineEdit);
+ shortcut_search_box->set_placeholder(TTR("Search"));
shortcut_search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hbc->add_child(shortcut_search_box);
shortcut_search_box->connect("text_changed", callable_mp(this, &EditorSettingsDialog::_filter_shortcuts));
diff --git a/editor/translations/af.po b/editor/translations/af.po
index 90dca850de..526fe331ae 100644
--- a/editor/translations/af.po
+++ b/editor/translations/af.po
@@ -1186,6 +1186,16 @@ msgid "Gold Sponsors"
msgstr "Goue Borge"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Silver Skenkers"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Brons Skenkers"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Mini Borge"
diff --git a/editor/translations/ar.po b/editor/translations/ar.po
index 075bc25f6e..d5b9ecc9d4 100644
--- a/editor/translations/ar.po
+++ b/editor/translations/ar.po
@@ -48,8 +48,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-08-11 14:04+0000\n"
-"Last-Translator: Musab Alasaifer <mousablasefer@gmail.com>\n"
+"PO-Revision-Date: 2020-08-20 15:20+0000\n"
+"Last-Translator: أحمد مصطÙÙ‰ الطبراني <eltabaraniahmed@gmail.com>\n"
"Language-Team: Arabic <https://hosted.weblate.org/projects/godot-engine/"
"godot/ar/>\n"
"Language: ar\n"
@@ -58,12 +58,12 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
-"X-Generator: Weblate 4.2-dev\n"
+"X-Generator: Weblate 4.2.1-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Invalid type argument to convert(), use TYPE_* constants."
-msgstr "معامل type خاطئ لدالة Convert, استخدم احدى الثوابت من مجموعة TYPE_*."
+msgstr "معامل خاطئ لدالة ()Convert, استخدم احدى الثوابت من مجموعة TYPE_*."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
@@ -157,11 +157,11 @@ msgstr "أدخل Ø§Ù„Ù…ÙØªØ§Ø­ هنا"
#: editor/animation_bezier_editor.cpp
msgid "Duplicate Selected Key(s)"
-msgstr "استنساخ Ø§Ù„Ù…ÙØ§ØªÙŠØ­ المحدد(Ø©)"
+msgstr "تكرار Ø§Ù„Ù…ÙØªØ§Ø­(Ø§Ù„Ù…ÙØ§ØªÙŠØ­) المحدد(Ø©)"
#: editor/animation_bezier_editor.cpp
msgid "Delete Selected Key(s)"
-msgstr "إمسح Ø§Ù„Ù…ÙØ§ØªÙŠØ­ المحدد(Ø©)"
+msgstr "إمسح Ø§Ù„Ù…ÙØªØ§Ø­(Ø§Ù„Ù…ÙØ§ØªÙŠØ­) المحدد(Ø©)"
#: editor/animation_bezier_editor.cpp
msgid "Add Bezier Point"
@@ -185,7 +185,7 @@ msgstr "تغيير وقت الإطار الرئيسي للحركة"
#: editor/animation_track_editor.cpp
msgid "Anim Change Transition"
-msgstr "تغيير إنتقالية التحريك"
+msgstr "تغيير إنتقالية الرسوم المتحركة"
#: editor/animation_track_editor.cpp
msgid "Anim Change Transform"
@@ -254,11 +254,11 @@ msgstr "شريط ضبط الحركة"
#: editor/animation_track_editor.cpp
msgid "Animation length (frames)"
-msgstr "مدة الحركة (frames)"
+msgstr "مدة الحركة (بالإطارات)"
#: editor/animation_track_editor.cpp
msgid "Animation length (seconds)"
-msgstr "مدة الحركة (seconds)"
+msgstr "مدة الحركة (بالثواني)"
#: editor/animation_track_editor.cpp
msgid "Add Track"
@@ -381,7 +381,7 @@ msgstr "حذ٠مسار التحريك"
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
-msgstr "أنشئ مسار جديد لـ %s Ùˆ أدخل Ù…ÙØªØ§Ø­ØŸ"
+msgstr "أنشئ مسار جديد لـ %s Ùˆ إدخال Ù…ÙØªØ§Ø­ØŸ"
#: editor/animation_track_editor.cpp
msgid "Create %d NEW tracks and insert keys?"
@@ -445,11 +445,11 @@ msgstr ""
#: editor/animation_track_editor.cpp
msgid "Animation tracks can only point to AnimationPlayer nodes."
-msgstr "مسارات الحركة يمكنها Ùقط أن تشير إلى عقد مشغّل الحركة."
+msgstr "مسارات الحركة يمكنها Ùقط أن تشير إلى عÙقد مشغّل الحركة."
#: editor/animation_track_editor.cpp
msgid "An animation player can't animate itself, only other players."
-msgstr "مشغل الحركة لا يمكنه تحريك Ù†ÙØ³Ù‡, Ùقط الاعبين الأخرين."
+msgstr "مشغل الحركة لا يمكنه أن يحرك Ù†ÙØ³Ù‡, Ùقط الاعبين الأخرين."
#: editor/animation_track_editor.cpp
msgid "Not possible to add a new track without a root"
@@ -457,11 +457,11 @@ msgstr "لا يمكن Ø¥Ø¶Ø§ÙØ© مقطع جديد بدون جذر"
#: editor/animation_track_editor.cpp
msgid "Invalid track for Bezier (no suitable sub-properties)"
-msgstr "مقطع غير متواÙÙ‚ مع منحنى بيزير Bezier (خصائص ÙØ±Ø¹ÙŠØ© غير متواÙقة)"
+msgstr "مقطع غير متواÙÙ‚ مع منحنى بيزر (Bezier) (خصائص ÙØ±Ø¹ÙŠØ© غير متواÙقة)"
#: editor/animation_track_editor.cpp
msgid "Add Bezier Track"
-msgstr "Ø¥Ø¶Ø§ÙØ© مسار لمنحنى بريزير"
+msgstr "Ø¥Ø¶Ø§ÙØ© مسار لمنحنى بيزر"
#: editor/animation_track_editor.cpp
msgid "Track path is invalid, so can't add a key."
@@ -469,7 +469,7 @@ msgstr "مسار المقطع غير صالح, إذن لا يمكن Ø¥Ø¶Ø§ÙØ© Ù
#: editor/animation_track_editor.cpp
msgid "Track is not of type Spatial, can't insert key"
-msgstr "المقطع ليس من نوع مكاني (Spatial), لا يمكن Ø¥Ø¶Ø§ÙØ© Ù…ÙØªØ§Ø­."
+msgstr "المقطع ليس من نوع مكاني (Spatial), لا يمكن Ø¥Ø¶Ø§ÙØ© Ù…ÙØªØ§Ø­"
#: editor/animation_track_editor.cpp
msgid "Add Transform Track Key"
@@ -497,7 +497,7 @@ msgstr "Ù…ÙØªØ§Ø­ حركة التحريك"
#: editor/animation_track_editor.cpp
msgid "Clipboard is empty"
-msgstr "ذاكرة التخزين المؤقت (Clipboard) ÙØ§Ø±ØºØ©"
+msgstr "Ø§Ù„Ø­Ø§ÙØ¸Ø© (Clipboard) ÙØ§Ø±ØºØ©"
#: editor/animation_track_editor.cpp
msgid "Paste Tracks"
@@ -510,7 +510,7 @@ msgstr "Ù…ÙØªØ§Ø­ تكبير حركة"
#: editor/animation_track_editor.cpp
msgid ""
"This option does not work for Bezier editing, as it's only a single track."
-msgstr "هذا الخيار لا يعمل لتعديل خط (Bezier), لأنه Ùقط مقطع واحد."
+msgstr "هذا الخيار لا يعمل لتعديل منحنى بيزر (Bezier), لأنه Ùقط مقطع واحد."
#: editor/animation_track_editor.cpp
msgid ""
@@ -524,12 +524,14 @@ msgid ""
"Alternatively, use an import preset that imports animations to separate "
"files."
msgstr ""
-"هذا الانيميشن ينتمي الى مشهد مستورد، لذا ÙØ¥Ù† أي تغييرات ÙÙŠ المسارات "
-"المستوردة لن يتم Ø­ÙØ¸Ù‡Ø§.\n"
+"هذه الحركة (رسوم متحركة) تنتمي الى مشهد مستورد، لذا ÙØ¥Ù† أي تغييرات ÙÙŠ "
+"المسارات المستوردة لن يتم Ø­ÙØ¸Ù‡Ø§.\n"
"\n"
"لتشغيل الامكانية Ù„Ø¥Ø¶Ø§ÙØ© مسارات خاصة، انتقل إلى إعدادات استيراد المشهد واضبط "
-"\"Animation > Storage\" إلى \"Files\"، شغل \"Animation > Keep Custom Tracks"
-"\"، ثم ..."
+"\"رسوم متحركة > تخزين\" إلى \"Ù…Ù„ÙØ§Øª\"ØŒ\n"
+"شغل \"رسوم متحركة > Ø£Ø­ØªÙØ¸ بالمقاطع (المسارات) المخصصة\"ØŒ ثم اعد الاستيراد.\n"
+"يمكنك ايضاً استخدام إعدادات استيراد مسبقة تقوم باستيراد الرسم المتحرك الى "
+"Ù…Ù„ÙØ§Øª Ù…ØªÙØ±Ù‚Ø©."
#: editor/animation_track_editor.cpp
msgid "Warning: Editing imported animation"
@@ -595,7 +597,7 @@ msgstr "تكرير المحدد"
#: editor/animation_track_editor.cpp
msgid "Duplicate Transposed"
-msgstr "نسخ محمّل"
+msgstr "نقل مكرر"
#: editor/animation_track_editor.cpp
msgid "Delete Selection"
@@ -623,7 +625,7 @@ msgstr "إختار العقدة التي سو٠يتم تحريكها:"
#: editor/animation_track_editor.cpp
msgid "Use Bezier Curves"
-msgstr "إستعمل منحنيات بيزية"
+msgstr "إستعمل منحنيات بيزر"
#: editor/animation_track_editor.cpp
msgid "Anim. Optimizer"
@@ -796,7 +798,7 @@ msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
msgstr ""
-"لم يتم العثور على الدالة Ø§Ù„Ù…Ø³ØªÙ‡Ø¯ÙØ©. حدّد دالة سليمة أو أرÙÙ‚ كود للعقدة "
+"لم يتم العثور على الدالة Ø§Ù„Ù…Ø³ØªÙ‡Ø¯ÙØ©. حدّد دالة سليمة أو أرÙÙ‚ نص برمجي للعقدة "
"Ø§Ù„Ù…Ø³ØªÙ‡Ø¯ÙØ©."
#: editor/connections_dialog.cpp
@@ -922,7 +924,7 @@ msgstr "تعديل الإتصال:"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from the \"%s\" signal?"
-msgstr "هل أنت(ي) متأكد(ة) أنك تود إزالة كل الإتصالات من الإشارة \"%s\"؟"
+msgstr "هل أنت متأكد أنك تود إزالة كل الإتصالات من الإشارة \"%s\"؟"
#: editor/connections_dialog.cpp editor/editor_help.cpp editor/node_dock.cpp
msgid "Signals"
@@ -930,7 +932,7 @@ msgstr "الإشارات"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from this signal?"
-msgstr "هل أنت(ي) متأكد(ة) أنك تود إزالة كل الإتصالات من هذه الإشارة؟"
+msgstr "هل أنت متأكد أنك تود إزالة كل الإتصالات من هذه الإشارة؟"
#: editor/connections_dialog.cpp
msgid "Disconnect All"
@@ -991,7 +993,7 @@ msgstr "البحث عن بديل لـ:"
#: editor/dependency_editor.cpp
msgid "Dependencies For:"
-msgstr "تابعة لـ:"
+msgstr "تبعيات لـ:"
#: editor/dependency_editor.cpp
msgid ""
@@ -1096,7 +1098,7 @@ msgstr "اخطاء ÙÙŠ التحميل!"
#: editor/dependency_editor.cpp
msgid "Permanently delete %d item(s)? (No undo!)"
-msgstr "إمسح نهائيا %d عنصر(عناصر)؟ (بلا رجعة!)"
+msgstr "هل تريد حذ٠%d عنصر (عناصر) نهائيًا؟ (لا تراجع!)"
#: editor/dependency_editor.cpp
msgid "Show Dependencies"
@@ -1132,11 +1134,11 @@ msgstr "تغيير قيمة ÙÙŠ القاموس"
#: editor/editor_about.cpp
msgid "Thanks from the Godot community!"
-msgstr "شكراً من مجتمع Godot!"
+msgstr "شكراً من مجتمع غودوت!"
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
-msgstr "المسهامين ÙÙŠ محرك Godot"
+msgstr "المسهامين ÙÙŠ محرك غودوت"
#: editor/editor_about.cpp
msgid "Project Founders"
@@ -1167,6 +1169,16 @@ msgid "Gold Sponsors"
msgstr "الرعاة الذهبيين"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "المانحين Ø§Ù„ÙØ¶ÙŠÙŠÙ†"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "المانحين البرنزيين"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "الرعاة الصغار"
@@ -1201,9 +1213,9 @@ msgid ""
"is an exhaustive list of all such third-party components with their "
"respective copyright statements and license terms."
msgstr ""
-"محرك \"Godot\" يعتمد على عدد من المكتبات و المكونات البرمجية لملاك اخرين و "
-"لكنها مجانية Ùˆ Ù…ÙØªÙˆØ­Ø© المصدر، Ùˆ كلها متÙقة مع شروط الاستخدام لرخصة \"MIT\". "
-"ÙÙŠ ما يلي قائمة تحوي جميع هذه المكونات Ø§Ø¶Ø§ÙØ© الى حقوق النشر Ùˆ شروط الاستخدام "
+"محرك غودوت يعتمد على عدد من المكتبات و المكونات البرمجية لملاك اخرين و لكنها "
+"مجانية Ùˆ Ù…ÙØªÙˆØ­Ø© المصدر، Ùˆ كلها متÙقة مع شروط الاستخدام لرخصة \"MIT\". ÙÙŠ ما "
+"يلي قائمة تحوي جميع هذه المكونات Ø§Ø¶Ø§ÙØ© الى حقوق النشر Ùˆ شروط الاستخدام "
"الخاصة بها."
#: editor/editor_about.cpp
@@ -1224,7 +1236,7 @@ msgstr "حدث خطأ Ø¹Ù†Ø¯ÙØªØ­ مل٠الحزمة بسبب أن الملÙ
#: editor/editor_asset_installer.cpp
msgid "%s (Already Exists)"
-msgstr "%s (موجود أصلاً!)"
+msgstr "%s (موجود Ø¨Ø§Ù„ÙØ¹Ù„!)"
#: editor/editor_asset_installer.cpp
msgid "Uncompressing Assets"
@@ -1269,39 +1281,39 @@ msgstr "أض٠تأثير"
#: editor/editor_audio_buses.cpp
msgid "Rename Audio Bus"
-msgstr "إعادة تسمية بيوس الصوت"
+msgstr "إعادة تسمية مسار الصوت"
#: editor/editor_audio_buses.cpp
msgid "Change Audio Bus Volume"
-msgstr "تغيير حجم صوت البيوس"
+msgstr "تغيير حجم صوت مسار الصوت"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Solo"
-msgstr "تبديل بيوس الصوت إلي ÙØ±Ø¯ÙŠ"
+msgstr "تبديل مسار الصوت إلي ÙØ±Ø¯ÙŠ"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Mute"
-msgstr "تبديل بيوس الصوت إلي صامت"
+msgstr "تبديل مسار الصوت إلي صامت"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Bypass Effects"
-msgstr "تبديل بيوس الصوت إلي موثرات التبديل"
+msgstr "تبديل مسار الصوت إلي موثرات التبديل"
#: editor/editor_audio_buses.cpp
msgid "Select Audio Bus Send"
-msgstr "حدد بيوس الصوت للإرسال"
+msgstr "حدد مسار الصوت للإرسال"
#: editor/editor_audio_buses.cpp
msgid "Add Audio Bus Effect"
-msgstr "أض٠موثرات إلي بيوس الصوت"
+msgstr "أض٠موثرات إلي مسار الصوت"
#: editor/editor_audio_buses.cpp
msgid "Move Bus Effect"
-msgstr "حرك مؤثر البيوس"
+msgstr "حرك ثأثير مسار الصوت"
#: editor/editor_audio_buses.cpp
msgid "Delete Bus Effect"
-msgstr "مسح تأثير البيوس"
+msgstr "مسح تأثير مسار الصوت"
#: editor/editor_audio_buses.cpp
msgid "Drag & drop to rearrange."
@@ -1321,7 +1333,7 @@ msgstr "تخطي"
#: editor/editor_audio_buses.cpp
msgid "Bus options"
-msgstr "إعدادات البيوس"
+msgstr "إعدادات مسار الصوت"
#: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp
@@ -1342,31 +1354,31 @@ msgstr "الصوت"
#: editor/editor_audio_buses.cpp
msgid "Add Audio Bus"
-msgstr "أض٠بيوس الصوت"
+msgstr "أض٠مسار الصوت"
#: editor/editor_audio_buses.cpp
msgid "Master bus can't be deleted!"
-msgstr "البيوس الأساسي لا يمكن مسحة!"
+msgstr "مسار الصوت الأساسي لا يمكن مسحة!"
#: editor/editor_audio_buses.cpp
msgid "Delete Audio Bus"
-msgstr "إمسح بيوس الصوت"
+msgstr "إمسح مسار الصوت"
#: editor/editor_audio_buses.cpp
msgid "Duplicate Audio Bus"
-msgstr "تكرير بيوس الصوت"
+msgstr "تكرار مسار الصوت"
#: editor/editor_audio_buses.cpp
msgid "Reset Bus Volume"
-msgstr "إرجاع صوت البيس"
+msgstr "إرجاع صوت المسار"
#: editor/editor_audio_buses.cpp
msgid "Move Audio Bus"
-msgstr "تحريك بيوس الصوت"
+msgstr "تحريك مسار الصوت"
#: editor/editor_audio_buses.cpp
msgid "Save Audio Bus Layout As..."
-msgstr "Ø¥Ø­ÙØ¸ نسق بيوس الصوت كـ..."
+msgstr "Ø­ÙØ¸ تخطيط مسار الصوت كـ…"
#: editor/editor_audio_buses.cpp
msgid "Location for New Layout..."
@@ -1374,7 +1386,7 @@ msgstr "المكان للنسق الجديد..."
#: editor/editor_audio_buses.cpp
msgid "Open Audio Bus Layout"
-msgstr "Ø¥ÙØªØ­ نسق بيوس الصوت"
+msgstr "Ø¥ÙØªØ­ نسق مسار الصوت"
#: editor/editor_audio_buses.cpp
msgid "There is no '%s' file."
@@ -1386,15 +1398,15 @@ msgstr "المخطط"
#: editor/editor_audio_buses.cpp
msgid "Invalid file, not an audio bus layout."
-msgstr "مل٠خطأ، ليس مل٠نسق بيوس الصوت."
+msgstr "مل٠خطأ، ليس مل٠نسق مسار الصوت."
#: editor/editor_audio_buses.cpp
msgid "Error saving file: %s"
-msgstr "خطأ !خطأ ÙÙŠ تسجيل الملÙ: s%"
+msgstr "خطأ ÙÙŠ تحميل الملÙ: s%"
#: editor/editor_audio_buses.cpp
msgid "Add Bus"
-msgstr "أض٠بيوس"
+msgstr "أض٠مسار"
#: editor/editor_audio_buses.cpp
msgid "Add a new Audio Bus to this layout."
@@ -1408,7 +1420,7 @@ msgstr "تحميل"
#: editor/editor_audio_buses.cpp
msgid "Load an existing Bus Layout."
-msgstr "تحميل نسق بيوس موجود مسبقاً."
+msgstr "تحميل نسق مسار موجود مسبقاً."
#: editor/editor_audio_buses.cpp
msgid "Save As"
@@ -1416,7 +1428,7 @@ msgstr "Ø­ÙØ¸ بأسم"
#: editor/editor_audio_buses.cpp
msgid "Save this Bus Layout to a file."
-msgstr "Ø¥Ø­ÙØ¸ نسق البيوس هذا إلي ملÙ."
+msgstr "Ø¥Ø­ÙØ¸ نسق هذا مسار إلي ملÙ."
#: editor/editor_audio_buses.cpp editor/import_dock.cpp
msgid "Load Default"
@@ -1424,11 +1436,11 @@ msgstr "تحميل Ø§Ù„Ø¥ÙØªØ±Ø§Ø¶ÙŠ"
#: editor/editor_audio_buses.cpp
msgid "Load the default Bus Layout."
-msgstr "تحميل نسق البيوس Ø§Ù„Ø¥ÙØªØ±Ø§Ø¶ÙŠ."
+msgstr "تحميل نسق المسار Ø§Ù„Ø¥ÙØªØ±Ø§Ø¶ÙŠ."
#: editor/editor_audio_buses.cpp
msgid "Create a new Bus Layout."
-msgstr "أنشئ نسق بيوس جديد."
+msgstr "أنشئ نسق مسار جديد."
#: editor/editor_autoload_settings.cpp
msgid "Invalid name."
@@ -1476,7 +1488,7 @@ msgstr "ازالة التحميل التلقائي"
#: editor/editor_autoload_settings.cpp editor/editor_plugin_settings.cpp
msgid "Enable"
-msgstr "تمكين"
+msgstr "ØªÙØ¹ÙŠÙ„"
#: editor/editor_autoload_settings.cpp
msgid "Rearrange Autoloads"
@@ -1484,7 +1496,7 @@ msgstr "اعادة ترتيب التحميلات التلقائية"
#: editor/editor_autoload_settings.cpp
msgid "Can't add autoload:"
-msgstr "لا يمكن Ø§Ø¶Ø§ÙØ© التحميل التلقائي"
+msgstr "لا يمكن Ø¥Ø¶Ø§ÙØ© التحميل التلقائي:"
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -1679,7 +1691,7 @@ msgstr "(Ø§Ù„Ù…ÙØ­Ø±Ø± Ù…ÙØ¹Ø·Ù‘Ù„)"
#: editor/editor_feature_profile.cpp
msgid "Class Options:"
-msgstr "إعدادات الص٠Class:"
+msgstr "إعدادات الص٠(Class):"
#: editor/editor_feature_profile.cpp
msgid "Enable Contextual Editor"
@@ -1748,7 +1760,7 @@ msgstr "إعدادات الص٠Class"
#: editor/editor_feature_profile.cpp
msgid "New profile name:"
-msgstr "اسم مَل٠profile جديد:"
+msgstr "اسم مَل٠(profile) جديد:"
#: editor/editor_feature_profile.cpp
msgid "Erase Profile"
@@ -1978,11 +1990,11 @@ msgstr "Ø§Ù„Ø§ÙØªØ±Ø§Ø¶ÙŠ:"
#: editor/editor_help.cpp
msgid "Methods"
-msgstr "قائمة الطرق"
+msgstr "Ø§Ù„Ø·ÙØ±Ù‚"
#: editor/editor_help.cpp
msgid "Theme Properties"
-msgstr "خصائص الثمة"
+msgstr "خصائص الثÙمة"
#: editor/editor_help.cpp
msgid "Enumerations"
@@ -2010,7 +2022,7 @@ msgstr ""
#: editor/editor_help.cpp
msgid "Method Descriptions"
-msgstr "أوصا٠الدوال Method"
+msgstr "أوصا٠الدوال"
#: editor/editor_help.cpp
msgid ""
@@ -2087,7 +2099,7 @@ msgstr "خاصية"
#: editor/editor_help_search.cpp
msgid "Theme Property"
-msgstr "خاصية الموضوع Theme"
+msgstr "خاصية الموضوع (Theme)"
#: editor/editor_inspector.cpp editor/project_settings_editor.cpp
msgid "Property:"
@@ -2232,7 +2244,7 @@ msgstr "Ø­ÙØ¸ المشهد"
#: editor/editor_node.cpp
msgid "Analyzing"
-msgstr "يحلل"
+msgstr "جاري التحليل"
#: editor/editor_node.cpp
msgid "Creating Thumbnail"
@@ -2240,7 +2252,7 @@ msgstr "ينشئ الصورة المصغرة"
#: editor/editor_node.cpp
msgid "This operation can't be done without a tree root."
-msgstr "هذه العملية لا يمكنها الإكتمال من غير جذر شجرة ."
+msgstr "هذه العملية لا يمكنها الإكتمال من غير شجرة رئيسة."
#: editor/editor_node.cpp
msgid ""
@@ -2386,7 +2398,7 @@ msgstr "يتطلب Ø­ÙØ¸ المشهد ØªÙˆØ§ÙØ± عÙقدة رئيسة."
#: editor/editor_node.cpp
msgid "Save Scene As..."
-msgstr "Ø­ÙØ¸ المشهد كـ..."
+msgstr "Ø­ÙØ¸ المشهد كـ…"
#: editor/editor_node.cpp
msgid "No"
@@ -2497,31 +2509,33 @@ msgstr "غير قادر علي ØªÙØ¹ÙŠÙ„ Ø¥Ø¶Ø§ÙØ© البرنامج Ø§Ù„Ù…ÙØ³
#: editor/editor_node.cpp
msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
msgstr ""
-"غير قادر علي إيجاد منطقة الكود من أجل Ø¥Ø¶Ø§ÙØ© البرنامج ÙÙŠ: 'res://addons/%s'."
+"غير قادر علي إيجاد منطقة النص البرمجي من أجل Ø¥Ø¶Ø§ÙØ© البرنامج ÙÙŠ: 'res://"
+"addons/%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
-msgstr "غير قادر علي تحميل كود Ø§Ù„Ø¥Ø¶Ø§ÙØ© من المسار: '%s'."
+msgstr "غير قادر علي تحميل النص البرمجي Ù„Ù„Ø¥Ø¶Ø§ÙØ© من المسار: '%s'."
#: editor/editor_node.cpp
msgid ""
"Unable to load addon script from path: '%s' There seems to be an error in "
"the code, please check the syntax."
msgstr ""
-"غير قادر علي تحميل كود Ø§Ù„Ø¥Ø¶Ø§ÙØ© من المسار: '%s' يبدو أن الكود يوجد Ùيه "
-"أخطاء , الرجاء مراجعة الكود."
+"غير قادر علي تحميل النص البرمجي Ø§Ù„Ø¥Ø¶Ø§ÙØ¨ من المسار: '%s' يبدو أن Ø´ÙÙØ±Ø© "
+"البرمجية يوجد بها أخطاء , الرجاء مراجعة الشÙÙØ±Ø© البرمجية."
#: editor/editor_node.cpp
msgid ""
"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
msgstr ""
-"غير قادر علي تحميل كود Ø§Ù„Ø¥Ø¶Ø§ÙØ© من المسار: '%s' النوع الأساسي ليس Ø¥Ø¶Ø§ÙØ© "
-"Ø§Ù„Ù…ÙØ¹Ø¯Ù„."
+"غير قادر علي تحميل النص البرمجي الإضاÙÙŠ من المسار: '%s' النوع الأساسي ليس "
+"Ø¥Ø¶Ø§ÙØ© Ø§Ù„Ù…ÙØ¹Ø¯Ù„."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
msgstr ""
-"غير قادر علي تحميل كود Ø§Ù„Ø¥Ø¶Ø§ÙØ© من المسار: '%s' الكود ليس ÙÙŠ وضع الأداة."
+"غير قادر علي تحميل النص البرمجي الإضاÙÙŠ من المسار: '%s' النص البرمجي ليس ÙÙŠ "
+"وضع الأداة."
#: editor/editor_node.cpp
msgid ""
@@ -2706,7 +2720,7 @@ msgstr "تحويل الي..."
#: editor/editor_node.cpp
msgid "MeshLibrary..."
-msgstr "مكتبة الميش..."
+msgstr "مكتبة المجسم..."
#: editor/editor_node.cpp
msgid "TileSet..."
@@ -2737,7 +2751,7 @@ msgstr "إعدادات المشروع..."
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Version Control"
-msgstr "التحكم ÙÙŠ الإصدار"
+msgstr "التحكم بالإصدار"
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Set Up Version Control"
@@ -2761,7 +2775,7 @@ msgstr "ÙØªØ­ مجلد بيانات المشروع"
#: editor/editor_node.cpp editor/plugins/tile_set_editor_plugin.cpp
msgid "Tools"
-msgstr "ادوات"
+msgstr "أدوات"
#: editor/editor_node.cpp
msgid "Orphan Resource Explorer..."
@@ -2769,7 +2783,7 @@ msgstr "Ù…ØªØµÙØ­ الموارد Ø£ÙˆØ±ÙØ§Ù†..."
#: editor/editor_node.cpp
msgid "Quit to Project List"
-msgstr "غادر إلى قائمه المشاريع"
+msgstr "العودة إلى قائمة المشاريع"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/project_export.cpp
@@ -2801,11 +2815,11 @@ msgid ""
"On Android, deploy will use the USB cable for faster performance. This "
"option speeds up testing for games with a large footprint."
msgstr ""
-"حينما يتم ØªÙØ¹ÙŠÙ„ هذا الإعداد، التصدير او النشر سو٠ينتج مل٠تشغيل بالحد "
-"الأدني.\n"
+"حينما يتم ØªÙØ¹ÙŠÙ„ هذا الإعداد، التصدير أو النشر سو٠ينتج مل٠تشغيل بالحد "
+"الأدنى (مبسط).\n"
"نظام Ø§Ù„Ù…Ù„ÙØ§Øª سو٠يتم توÙيره بواسطة Ø§Ù„Ù…ÙØ¹Ø¯Ù„ من خلال الشبكة.\n"
-"علي الأندرويد، النشر سو٠يستخدم وصلة اليو اس بي من أجل أداء أسرع. هذا "
-"الأعداد يسرع الإختبار للإلعاب مع Ø§Ù„Ù…Ù„ÙØ§Øª الكثيرة."
+"على الأندرويد، النشر سو٠يستخدم وصلة اليو إس بي من أجل أداء أسرع. هذا "
+"الإعداد يسرّع إختبار الألعاب ذو الحجم الكبير."
#: editor/editor_node.cpp
msgid "Visible Collision Shapes"
@@ -2816,8 +2830,8 @@ msgid ""
"Collision shapes and raycast nodes (for 2D and 3D) will be visible on the "
"running game if this option is turned on."
msgstr ""
-"أشكال الإصطدام Ùˆ وعقد الراي كاست (من أجل 2D Ùˆ 3D) سو٠تكون ظاهرة ÙÙŠ اللعبة "
-"العاملة إذا كان هذا الإعداد Ù…ÙÙØ¹Ù„."
+"أشكال الإصطدام Ùˆ عÙقد الراي كاست (من أجل 2D Ùˆ 3D) سو٠تكون ظاهرة ÙÙŠ اللعبة "
+"العاملة إذا كان هذا الإعداد Ù…ÙÙØ¹Ù‘Ù„."
#: editor/editor_node.cpp
msgid "Visible Navigation"
@@ -2827,7 +2841,8 @@ msgstr "الإنتقال المرئي"
msgid ""
"Navigation meshes and polygons will be visible on the running game if this "
"option is turned on."
-msgstr "ميشات التنقل والبوليجين سو٠يكونون ظاهرين حينما يتم ØªÙØ¹ÙŠÙ„ هذا الإعداد."
+msgstr ""
+"مجسمات التنقل والأشكال المضلعة سو٠تكون ظاهرة حينما يتم ØªÙØ¹ÙŠÙ„ هذا الإعداد."
#: editor/editor_node.cpp
msgid "Sync Scene Changes"
@@ -2856,22 +2871,22 @@ msgid ""
"When used remotely on a device, this is more efficient with network "
"filesystem."
msgstr ""
-"حينما يكون هذا الإعداد Ù…ÙÙØ¹Ù„ØŒ أي كود يتم Ø­ÙØ¸Ù‡ سيتم إعادة تشغيلة ÙÙŠ اللعبة "
-"العاملة.\n"
-"حينما يتم إستخدامة عن بعد علي جهاز، سيكون هذا أكثر ÙØ¹Ø§Ù„ية مع نظام شبكات "
+"حينما يكون هذا الإعداد Ù…ÙÙØ¹Ù„ØŒ أي نص برمجي يتم Ø­ÙØ¸Ù‡ سيتم إعادة تحميله ÙÙŠ "
+"اللعبة العاملة.\n"
+"حينما يتم إستخدامه عن Ø¨ÙØ¹Ø¯ على جهاز، سيكون هذا أكثر ÙØ¹Ø§Ù„ية مع نظام شبكات "
"Ø§Ù„Ù…Ù„ÙØ§Øª."
#: editor/editor_node.cpp editor/script_create_dialog.cpp
msgid "Editor"
-msgstr "Ø§Ù„Ù…ÙØ¹Ø¯Ù„"
+msgstr "المحرّر"
#: editor/editor_node.cpp
msgid "Editor Settings..."
-msgstr "إعدادات المحرّر"
+msgstr "إعدادات المحرّر…"
#: editor/editor_node.cpp
msgid "Editor Layout"
-msgstr "نسق Ø§Ù„Ù…ÙØ¹Ø¯Ù„"
+msgstr "تنسيق المحرّر"
#: editor/editor_node.cpp
msgid "Take Screenshot"
@@ -2879,11 +2894,11 @@ msgstr "أخذ صورة للشاشة"
#: editor/editor_node.cpp
msgid "Screenshots are stored in the Editor Data/Settings Folder."
-msgstr "لقطات الشاشة تكون محÙوظة ÙÙŠ مجلّد البيانات/الإعدادت داخل المحرّر"
+msgstr "لقطات الشاشة تكون محÙوظة ÙÙŠ مجلّد بيانات/إعدادات المحرّر."
#: editor/editor_node.cpp
msgid "Toggle Fullscreen"
-msgstr "إلغاء/ØªÙØ¹ÙŠÙ„ وضع الشاشة الكاملة"
+msgstr "ØªÙØ¹ÙŠÙ„/إلغاء وضع الشاشة الكاملة"
#: editor/editor_node.cpp
msgid "Toggle System Console"
@@ -2891,11 +2906,11 @@ msgstr "إظهار/Ø¥Ø®ÙØ§Ø¡ وحدة التحكم بالنظام"
#: editor/editor_node.cpp
msgid "Open Editor Data/Settings Folder"
-msgstr "ÙØªØ­ مجلّد البيانات/الإعدادت المحرّر"
+msgstr "ÙØªØ­ مجلّد بيانات/إعدادات المحرّر"
#: editor/editor_node.cpp
msgid "Open Editor Data Folder"
-msgstr "Ø§ÙØªØ­ مل٠بيانات المحرر"
+msgstr "ÙØªØ­ مجلّد بيانات المحرّر"
#: editor/editor_node.cpp
msgid "Open Editor Settings Folder"
@@ -2903,7 +2918,7 @@ msgstr "ÙØªØ­ مجلّد إعدادات المحرّر"
#: editor/editor_node.cpp
msgid "Manage Editor Features..."
-msgstr "إدارة ميّزات المحرّر"
+msgstr "إدارة ميّزات المحرّر…"
#: editor/editor_node.cpp
msgid "Manage Export Templates..."
@@ -2933,7 +2948,7 @@ msgstr "الأسئلة و الأجوبة"
#: editor/editor_node.cpp
msgid "Report a Bug"
-msgstr "إرسال تقرير عن bug أو خلل ÙÙŠ شيء ما"
+msgstr "إرسال تقرير عن خلل برمجي"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
@@ -2945,7 +2960,7 @@ msgstr "المجتمع"
#: editor/editor_node.cpp
msgid "About"
-msgstr "عن"
+msgstr "عن هذا التطبيق"
#: editor/editor_node.cpp
msgid "Play the project."
@@ -2957,11 +2972,11 @@ msgstr "تشغيل"
#: editor/editor_node.cpp
msgid "Pause the scene execution for debugging."
-msgstr "إيقا٠جلسة المشهد من أجل تنقيح الكبوات البرمجية debugging."
+msgstr "إيقا٠المشهد الحالي من أجل المعالجة البرمجية."
#: editor/editor_node.cpp
msgid "Pause Scene"
-msgstr "إيقا٠مؤقت للمشهد"
+msgstr "إيقا٠مؤقّت للمشهد"
#: editor/editor_node.cpp
msgid "Stop the scene."
@@ -2969,7 +2984,7 @@ msgstr "إيقا٠المشهد."
#: editor/editor_node.cpp
msgid "Play the edited scene."
-msgstr "تشغيل المشهد Ø§Ù„Ù…ÙØ¹Ø¯Ù„."
+msgstr "تشغيل المشهد Ø§Ù„Ù…ÙØ¹Ø¯Ù‘Ù„."
#: editor/editor_node.cpp
msgid "Play Scene"
@@ -2994,7 +3009,7 @@ msgstr "Ø­ÙØ¸ Ùˆ إعادة تشغيل"
#: editor/editor_node.cpp
msgid "Spins when the editor window redraws."
-msgstr "يدور حينما يتم إعادة رسم Ù†Ø§ÙØ°Ø© المحرّر"
+msgstr "قم بالتدوير أثناء إعادة رسم Ù†Ø§ÙØ°Ø© المحرّر."
#: editor/editor_node.cpp
msgid "Update Continuously"
@@ -3014,7 +3029,7 @@ msgstr "نظام Ø§Ù„Ù…Ù„ÙØ§Øª"
#: editor/editor_node.cpp
msgid "Inspector"
-msgstr "Ù…ÙØ±Ø§Ù‚ب"
+msgstr "Ø§Ù„Ù…ÙØ±Ø§Ù‚ب"
#: editor/editor_node.cpp
msgid "Expand Bottom Panel"
@@ -3099,27 +3114,27 @@ msgstr "حدد"
#: editor/editor_node.cpp
msgid "Open 2D Editor"
-msgstr "ÙØªØ­ Ø§Ù„Ù…ÙØ¹Ø¯Ù„ 2D"
+msgstr "ÙØªØ­ Ø§Ù„Ù…ÙØ­Ø±Ø± 2D"
#: editor/editor_node.cpp
msgid "Open 3D Editor"
-msgstr "ÙØªØ­ Ø§Ù„Ù…ÙØ¹Ø¯Ù„ 3D"
+msgstr "ÙØªØ­ Ø§Ù„Ù…ÙØ­Ø±Ø± 3D"
#: editor/editor_node.cpp
msgid "Open Script Editor"
-msgstr "ÙØªØ­ Ù…ÙØ¹Ø¯Ù„ الكود"
+msgstr "ÙØªØ­ محرر النص البرمجي"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "Open Asset Library"
-msgstr "ÙØªØ­ مكتبة الأصول"
+msgstr "ÙØªØ­ مكتبة المÙلحقات"
#: editor/editor_node.cpp
msgid "Open the next Editor"
-msgstr "ÙØªØ­ ÙÙŠ Ø§Ù„Ù…ÙØ¹Ø¯Ù„ التالي"
+msgstr "ÙØªØ­ ÙÙŠ Ø§Ù„Ù…ÙØ­Ø±Ø± التالي"
#: editor/editor_node.cpp
msgid "Open the previous Editor"
-msgstr "Ø¥ÙØªØ­ Ø§Ù„Ù…ÙØ¹Ø¯Ù„ السابق"
+msgstr "Ø¥ÙØªØ­ Ø§Ù„Ù…ÙØ­Ø±Ø± السابق"
#: editor/editor_node.h
msgid "Warning!"
@@ -3236,7 +3251,7 @@ msgstr "إلحاق..."
#: editor/editor_properties.cpp
msgid "Invalid RID"
-msgstr "إسم RID غير صالح."
+msgstr "RID غير صالح"
#: editor/editor_properties.cpp
msgid ""
@@ -3584,7 +3599,7 @@ msgstr "حدد مل٠القالب"
#: editor/export_template_manager.cpp
msgid "Godot Export Templates"
-msgstr "إدارة قوالب التصدير Godot"
+msgstr "إدارة قوالب التصدير لغودوت"
#: editor/export_template_manager.cpp
msgid "Export Template Manager"
@@ -3708,11 +3723,11 @@ msgstr "مشهد جديد..."
#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
msgid "New Script..."
-msgstr "ÙØªØ­ السكريبت..."
+msgstr "ÙØªØ­ النص البرمجي..."
#: editor/filesystem_dock.cpp
msgid "New Resource..."
-msgstr "مورد جديد..."
+msgstr "مصدر جديد..."
#: editor/filesystem_dock.cpp editor/plugins/visual_shader_editor_plugin.cpp
#: editor/script_editor_debugger.cpp
@@ -3733,7 +3748,7 @@ msgstr "إعادة التسمية"
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
-msgstr "‪المجلد/المل٠السابق"
+msgstr "المجلد/المل٠السابق"
#: editor/filesystem_dock.cpp
msgid "Next Folder/File"
@@ -3793,7 +3808,7 @@ msgstr "مجلد:"
#: editor/find_in_files.cpp
msgid "Filters:"
-msgstr "Ùلتر:"
+msgstr "تنقيات:"
#: editor/find_in_files.cpp
msgid ""
@@ -3822,7 +3837,7 @@ msgstr "إيجاد: "
#: editor/find_in_files.cpp
msgid "Replace: "
-msgstr "إستبدال:"
+msgstr "إستبدال: "
#: editor/find_in_files.cpp
msgid "Replace all (no undo)"
@@ -3895,7 +3910,7 @@ msgstr "إستيراد كمشهد واحد"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Animations"
-msgstr "إستيراد مع إنميشن Ù…Ù†ÙØµÙ„Ø©"
+msgstr "إستيراد مع رسوم متحركة Ù…Ù†ÙØµÙ„Ø©"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Materials"
@@ -3911,15 +3926,15 @@ msgstr "إستيراد مع عناصر+موارد Ù…Ù†ÙØµÙ„Ø©"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Objects+Animations"
-msgstr "إستيراد مع عناصر + إنميشن Ù…Ù†ÙØµÙ„Ø©"
+msgstr "إستيراد مع عناصر + رسوم متحركة Ù…Ù†ÙØµÙ„Ø©"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Materials+Animations"
-msgstr "إستيراد مع مصادر+ إنميشن Ù…Ù†ÙØµÙ„Ø©"
+msgstr "إستيراد مع مصادر+ رسوم متحركة Ù…Ù†ÙØµÙ„Ø©"
#: editor/import/resource_importer_scene.cpp
msgid "Import with Separate Objects+Materials+Animations"
-msgstr "إستيراد مع عناصر + مصادر + إنميشين Ù…Ù†ÙØµÙ„ين"
+msgstr "إستيراد مع عناصر + مصادر + رسوم متحركة Ù…Ù†ÙØµÙ„ين"
#: editor/import/resource_importer_scene.cpp
msgid "Import as Multiple Scenes"
@@ -3944,23 +3959,23 @@ msgstr "انشاء خارطة الضوء"
#: editor/import/resource_importer_scene.cpp
msgid "Generating for Mesh: "
-msgstr "انشاء من اجل الميش: "
+msgstr "انشاء من اجل المجسم: "
#: editor/import/resource_importer_scene.cpp
msgid "Running Custom Script..."
-msgstr "تشغيل الكود Ø§Ù„Ù…ÙØ®ØµØµ..."
+msgstr "تشغيل النص البرمجي Ø§Ù„Ù…ÙØ®ØµØµ..."
#: editor/import/resource_importer_scene.cpp
msgid "Couldn't load post-import script:"
-msgstr "لا يمكن تحميل الكود المستورد أو المطبوع:"
+msgstr "لا يمكن تحميل النص البرمجي المستورد أو المطبوع:"
#: editor/import/resource_importer_scene.cpp
msgid "Invalid/broken script for post-import (check console):"
-msgstr "كود مستورد-ملصق متضرر/خاطئ (تحقق من وحدة التحكم):"
+msgstr "النص البرمجي مستورد-ملصق متضرر/خاطئ (تحقق من وحدة التحكم):"
#: editor/import/resource_importer_scene.cpp
msgid "Error running post-import script:"
-msgstr "خطأ ÙÙŠ تشغيل الكود الملصق- المستورد:"
+msgstr "خطأ ÙÙŠ تشغيل النص البرمجي الملصق- المستورد:"
#: editor/import/resource_importer_scene.cpp
msgid "Did you return a Node-derived object in the `post_import()` method?"
@@ -3980,15 +3995,15 @@ msgstr "حدد ÙƒØ¥ÙØªØ±Ø§Ø¶ÙŠ Ù…Ù† أجل '%s'"
#: editor/import_dock.cpp
msgid "Clear Default for '%s'"
-msgstr "إخلاء Ø§Ù„Ø¥ÙØªØ±Ø§Ø¶ÙŠ Ù„Ù€ '%s'"
+msgstr "إخلاء Ø§Ù„Ø¥ÙØªØ±Ø§Ø¶ÙŠ Ù„ '%s'"
#: editor/import_dock.cpp
msgid "Import As:"
-msgstr "إستيراد كـ:"
+msgstr "إستيراد ك:"
#: editor/import_dock.cpp
msgid "Preset"
-msgstr "إعداد Ù…ÙØ³Ø¨Ù‚..."
+msgstr "إعداد Ù…ÙØ³Ø¨Ù‚"
#: editor/import_dock.cpp
msgid "Reimport"
@@ -4429,38 +4444,38 @@ msgstr "إلغاء/ØªÙØ¹ÙŠÙ„ التشغيل التلقائي"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "New Animation Name:"
-msgstr "إسم الحركة الجديد:"
+msgstr "إسم رسم المتحرك جديد:"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "New Anim"
-msgstr "حركة جديدة"
+msgstr "رسم متحرك جديدة"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Change Animation Name:"
-msgstr "تغيير إسم الحركة:"
+msgstr "تغيير إسم الرسم المتحرك:"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Delete Animation?"
-msgstr "مسح الحركة؟"
+msgstr "مسح الرسم المتحرك؟"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Remove Animation"
-msgstr "مسح الحركة"
+msgstr "مسح الرسم المتحرك"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Invalid animation name!"
-msgstr "خطأ: إسم الرسوم المتحركة خاطئ!"
+msgstr "إسم الرسم المتحرك خاطئ!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation name already exists!"
-msgstr "اسم الحركة موجود Ø¨Ø§Ù„ÙØ¹Ù„!"
+msgstr "إسم الرسم المتحرك موجود Ø¨Ø§Ù„ÙØ¹Ù„!"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Rename Animation"
-msgstr "إعادة تسمية الحركة"
+msgstr "إعادة تسمية الرسم المتحرك"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Blend Next Changed"
@@ -4472,23 +4487,23 @@ msgstr "تغيير وقت الدمج"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Load Animation"
-msgstr "تحميل حركة"
+msgstr "تحميل الرسم المتحرك"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Duplicate Animation"
-msgstr "تكرير الحركة"
+msgstr "تكرار الرسم المتحرك"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "No animation to copy!"
-msgstr "لا حركة رسومية لنسخها!"
+msgstr "لا رسم متحرك لنسخها!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "No animation resource on clipboard!"
-msgstr "لا يوجد مورد لرسومية متحركة ÙÙŠ Ø§Ù„Ø­Ø§ÙØ¸Ø© clipboard!"
+msgstr "لا يوجد مورد لرسم متحرك ÙÙŠ Ø§Ù„Ø­Ø§ÙØ¸Ø© clipboard!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Pasted Animation"
-msgstr "الحركة الرسومية المÙلصقة"
+msgstr "تم لصق الرسوم المتحركة"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Paste Animation"
@@ -4500,39 +4515,39 @@ msgstr "لا رسومات متحركة لتحريرها!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Play selected animation backwards from current pos. (A)"
-msgstr "تشغيل الحركة المختارة بشكل عكسي من الموقع الحالي. (زر A)"
+msgstr "تشغيل الرسم المتحرك المختار بشكل عكسي من الموقع الحالي. (زر A)"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Play selected animation backwards from end. (Shift+A)"
-msgstr "تشيل الحركة المختارة بشكل عكسي من النهاية. (Shift+ش)"
+msgstr "تشغيل الرسم المتحرك المختار بشكل عكسي من النهاية. (Shift+A)"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Stop animation playback. (S)"
-msgstr "إيقا٠تشغيل الحركة. (س)"
+msgstr "إيقا٠تشغيل الرسم المتحرك. (S)"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Play selected animation from start. (Shift+D)"
-msgstr "تشغيل الحركة المحددة من البداية. (Shift+ي)"
+msgstr "تشغيل الرسم المتحرك المحدد من البداية. (Shift+D)"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Play selected animation from current pos. (D)"
-msgstr "تشغيل الحركة المختارة من الموقع الحالي. (زر D)"
+msgstr "تشغيل الرسم المتحرك المختار من الموقع الحالي. (D)"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation position (in seconds)."
-msgstr "موقع الحركة (بالثواني)."
+msgstr "موقع الرسم المتحرك (بالثواني)."
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Scale animation playback globally for the node."
-msgstr "تكبير تشغيل الحركة عالمياً من العقدة."
+msgstr "تكبير تشغيل الرسم المتحرك عالمياً من العقدة."
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation Tools"
-msgstr "أدوات الحركة"
+msgstr "أدوات الرسم المتحرك"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation"
-msgstr "صورة متحركة"
+msgstr "الرسم المتحرك"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Edit Transitions..."
@@ -4604,11 +4619,11 @@ msgstr "تثبيت Ù…ÙØ´ØºÙ‘Ù„ الرسوميات المتحركة"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Create New Animation"
-msgstr "إنشاء حركة جديدة"
+msgstr "إنشاء رسوم متحركة جديدة"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation Name:"
-msgstr "إسم الحركة:"
+msgstr "إسم الرسم المتحرك:"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/resource_preloader_editor_plugin.cpp
@@ -4858,7 +4873,7 @@ msgstr "عقدة التنقل"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Import Animations..."
-msgstr "إستيراد الحركة..."
+msgstr "إستيراد الرسوم المتحركة..."
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Edit Node Filters"
@@ -4922,7 +4937,7 @@ msgstr "ÙØ´Ù„ الطلب ØŒ انتهت المهلة"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Timeout."
-msgstr "إنتهى الوقت"
+msgstr "انتهت المهلة."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Bad download hash, assuming file has been tampered with."
@@ -4962,7 +4977,7 @@ msgstr "خطأ ÙÙŠ إنشاء الطلب"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Idle"
-msgstr "عاطل"
+msgstr "الخمول (idle)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Install..."
@@ -7320,7 +7335,6 @@ msgid "Audio Listener"
msgstr "المستمع الصوتي"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Enable Doppler"
msgstr "ØªÙØ¹ÙŠÙ„ دوبلر"
@@ -7548,7 +7562,6 @@ msgid "View Z-Near:"
msgstr "إظهار Z-Near:"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "View Z-Far:"
msgstr "إظهار Z-Far:"
@@ -7655,9 +7668,8 @@ msgid "Invalid geometry, can't create light occluder."
msgstr "هندسياً غير صالح، لا يمكن إنشاء Ø­ÙØ¸Ø§Ø± (occluder) الضوء."
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Create LightOccluder2D Sibling"
-msgstr "أنشئ شكل Ù…ÙØ·Ø¨Ù‚"
+msgstr "أنشاء ضوء محجوب ثنائي الأبعاد"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Sprite"
@@ -7918,7 +7930,7 @@ msgstr "عنصر Ù…ÙÙØ¹Ù„ اختياري"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Named Sep."
-msgstr "Ø§Ù„ÙØ§ØµÙ„ Ø§Ù„Ù…ÙØ³Ù…ّى"
+msgstr "Ø§Ù„ÙØ§ØµÙ„ Ø§Ù„Ù…ÙØ³Ù…ّى."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Submenu"
@@ -7998,9 +8010,8 @@ msgid "Erase Selection"
msgstr "إزالة عملية الاختيار"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Fix Invalid Tiles"
-msgstr "اسم غير صالح."
+msgstr "أصلح البلاطة غير الصالحة"
#: editor/plugins/tile_map_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
@@ -8028,9 +8039,8 @@ msgid "Erase TileMap"
msgstr "مسح خريطة البلاط TileMap"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Find Tile"
-msgstr "جد"
+msgstr "جد البلاطة"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Transpose"
@@ -8045,9 +8055,8 @@ msgid "Enable Priority"
msgstr "تمكين الأولوية"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Filter tiles"
-msgstr "Ùلتر Ø§Ù„Ù…Ù„ÙØ§Øª..."
+msgstr "تنقية البلاطات"
#: editor/plugins/tile_map_editor_plugin.cpp
msgid "Give a TileSet resource to this TileMap to use its tiles."
@@ -8095,9 +8104,8 @@ msgid "Add Texture(s) to TileSet."
msgstr "Ø¥Ø¶Ø§ÙØ© نقش(نقوش) إلى Ù…ÙØ­Ø¯Ø¯ البلاط TileSet."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Remove selected Texture from TileSet."
-msgstr "مسح المدخلة الحالية"
+msgstr "مسح النقش Ø§Ù„Ù…ÙØ®ØªØ§Ø± من رزمة البلاطات."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create from Scene"
@@ -8112,9 +8120,8 @@ msgid "New Single Tile"
msgstr "بلاطة Ù…ÙÙØ±Ø¯Ø© جديدة"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "New Autotile"
-msgstr "إظهار Ø§Ù„Ù…Ù„ÙØ§Øª"
+msgstr "بلاط-تلقائي جديد"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "New Atlas"
@@ -8150,23 +8157,23 @@ msgstr "الإطباق Occlusion"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Navigation"
-msgstr "Ø§Ù„ØªØµÙØ­"
+msgstr "التنقل"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Bitmask"
-msgstr "قناع Ø§Ù„Ø¨ÙØª Bitmask"
+msgstr "قناع Ø§Ù„Ø¨ÙØª"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Priority"
-msgstr "Ø§Ù„ØªÙØ§Ø¶Ù„ Priority"
+msgstr "الأولية"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Z Index"
-msgstr "تراتبية المحور Z"
+msgstr "ترتيبية المحور Z"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Region Mode"
-msgstr "وضع الأقليم Region"
+msgstr "وضع الأقليم"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Collision Mode"
@@ -8174,19 +8181,19 @@ msgstr "وضع التصادم"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Occlusion Mode"
-msgstr "وضع الإطباق Occlusion"
+msgstr "وضع الإطباق"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Navigation Mode"
-msgstr "وضع Ø§Ù„ØªØµÙØ­"
+msgstr "وضع التنقل"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Bitmask Mode"
-msgstr "وضع Bitmask"
+msgstr "وضع قناع-Ø§Ù„Ø¨ÙØª"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Priority Mode"
-msgstr "وضع Ø§Ù„ØªÙØ§Ø¶Ù„ Priority"
+msgstr "وضع الأولية"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Icon Mode"
@@ -8194,21 +8201,19 @@ msgstr "وضع الأيقونة"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Z Index Mode"
-msgstr "وضع Z Index"
+msgstr "وضع ترتيبية المحور Z"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Copy bitmask."
-msgstr "نسخ bitmask."
+msgstr "نسخ قناع-Ø§Ù„Ø¨ÙØª."
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Paste bitmask."
-msgstr "لصق الحركة"
+msgstr "لصق قناع-Ø§Ù„Ø¨ÙØª"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Erase bitmask."
-msgstr "زر Ø§Ù„ÙØ£Ø±Ø© الأيمن: مسح النقطة."
+msgstr "مسح قناع-Ø§Ù„Ø¨ÙØª."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Create a new rectangle."
@@ -8497,7 +8502,7 @@ msgstr "الحالة"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "View file diffs before committing them to the latest version"
-msgstr "إظهار آخر تعديلات المل٠قبل قبولهم ÙÙŠ آخر نسخة."
+msgstr "إظهار آخر تعديلات المل٠قبل قبولهم ÙÙŠ آخر نسخة"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "No file diff is active"
@@ -8846,11 +8851,11 @@ msgstr "ثابت جذر-العدد2 (1.414214)، أي قيمة جذر العدد
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the absolute value of the parameter."
-msgstr "يحسب القيمة المطلقة لقيمة المَعلم."
+msgstr "ÙŠÙØ±Ø¬Ø¹ القيمة المطلقة لقيمة المَعلم."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the arc-cosine of the parameter."
-msgstr "ÙŠÙØ±Ø¬Ø¹ قيمة جيب التمام \"arc-cosine\" للمَعلم."
+msgstr "ÙŠÙØ±Ø¬Ø¹ قيمة جيب التمام للمَعلم."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the inverse hyperbolic cosine of the parameter."
@@ -8866,11 +8871,11 @@ msgstr "ÙŠÙØ±Ø¬Ø¹ قيمة جيب القطع الزائد العكسي للمَ
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the arc-tangent of the parameter."
-msgstr "ÙŠÙØ±Ø¬Ø¹ قيمة ظل الزاوية العكسية \"arc-tangent\" للمَعلم."
+msgstr "ÙŠÙØ±Ø¬Ø¹ قيمة ظل الزاوية العكسية للمَعلم."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the arc-tangent of the parameters."
-msgstr "ÙŠÙØ±Ø¬Ø¹ قيمة ظل الزاوية العكسي \"arc-tangent\" للمعالم."
+msgstr "ÙŠÙØ±Ø¬Ø¹ قيمة ظل الزاوية العكسي للمَعالم."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the inverse hyperbolic tangent of the parameter."
@@ -8900,11 +8905,11 @@ msgstr "يحوّل قيمة (كمية) من الراديان إلى الدرجا
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Base-e Exponential."
-msgstr "الدالة Base-e."
+msgstr "الدالة الأسية Base-e."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Base-2 Exponential."
-msgstr "الدالة Base-2."
+msgstr "الدالة الأسية Base-2."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the nearest integer less than or equal to the parameter."
@@ -8953,7 +8958,7 @@ msgstr "ÙŠÙØ±Ø¬Ø¹ قيمة المَعلم الأول مرÙوعاً إلى قو
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Converts a quantity in degrees to radians."
-msgstr "يحول الكمية المقاسة بالدرجات إلى الراديان."
+msgstr "يحول الكمية المقاسة بالدرجات إلى الراديان (الدائري)."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "1.0 / scalar"
@@ -8977,11 +8982,11 @@ msgstr "يستخرج إشارة المَعلم."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the sine of the parameter."
-msgstr "ÙŠÙØ±Ø¬Ø¹ جيب sine المَعلم parameter."
+msgstr "ÙŠÙØ±Ø¬Ø¹ جيب المَعلم."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the hyperbolic sine of the parameter."
-msgstr "ÙŠÙØ±Ø¬Ø¹ قيمة الجيب العكس hyperbolic sine للمَعلم."
+msgstr "ÙŠÙØ±Ø¬Ø¹ قيمة الجيب العكس للمَعلم."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the square root of the parameter."
@@ -9014,15 +9019,15 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the tangent of the parameter."
-msgstr "ÙŠÙØ±Ø¬Ø¹ قيمة ظل الزاوية tangent للمَعلم."
+msgstr "ÙŠÙØ±Ø¬Ø¹ قيمة ظل الزاوية للمَعلم."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the hyperbolic tangent of the parameter."
-msgstr "ÙŠÙØ±Ø¬Ø¹ قيمة ظل الزاوية العكسي hyperbolic tangent للمَعلم."
+msgstr "ÙŠÙØ±Ø¬Ø¹ قيمة ظل الزاوية العكسي للمَعلم."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the truncated value of the parameter."
-msgstr "يجد قيمة الاقتطاع truncated للمَعلم."
+msgstr "يجد قيمة الاقتطاع للمَعلم."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Adds scalar to scalar."
@@ -9061,7 +9066,6 @@ msgid "Perform the texture lookup."
msgstr "إجراء البحث عن النقش."
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Cubic texture uniform lookup."
msgstr "البحث عن النقش المكعبي الموحد."
@@ -9150,7 +9154,7 @@ msgstr "Ùكّ تركيب Ø§Ù„Ù…ÙØªØ¬Ù‡ إلى ثلاث كميات قياسية
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the cross product of two vectors."
-msgstr "حساب المنتوج الوسيط Ù„Ù„Ù…ÙØªØ¬Ù‡ÙŠÙ†."
+msgstr "حساب حاصل الضرب الاتجاهي لمتجهين."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the distance between two points."
@@ -9273,7 +9277,7 @@ msgstr "جداء (Ù…Ø¶Ø§Ø¹ÙØ©) Ù…ÙØªØ¬Ù‡ Ø¨Ù…ÙØªØ¬Ù‡."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the remainder of the two vectors."
-msgstr "ÙŠÙØ±Ø¬Ø¹ باقي كل من Ø§Ù„Ù…ÙØªØ¬Ù‡ÙŠÙ† (الشعاعين)."
+msgstr "ÙŠÙØ±Ø¬Ø¹ باقي قسمة كل من Ø§Ù„Ù…ÙØªØ¬Ù‡ÙŠÙ† (الشعاعين)."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Subtracts vector from vector."
@@ -9945,7 +9949,7 @@ msgid ""
"Invalid action name. it cannot be empty nor contain '/', ':', '=', '\\' or "
"'\"'"
msgstr ""
-"اسم ÙØ¹Ø§Ù„ية غير صحيح. لا يمكن أن يكون ÙØ§Ø±ØºØ§Ù‹ أو يتضمن '/'ØŒ ':'ØŒ '='ØŒ '\\' أو "
+"اسم ÙØ¹Ø§Ù„ية غير صحيح. لا يمكن أن يكون ÙØ§Ø±ØºØ§Ù‹ أو يتضمن '/'ØŒ ':'ØŒ '='ØŒ '\\' أو "
"'\"'"
#: editor/project_settings_editor.cpp
@@ -10530,7 +10534,7 @@ msgstr "حذ٠العÙقدة %d مع جميع أبنائها؟"
#: editor/scene_tree_dock.cpp
msgid "Delete %d nodes?"
-msgstr "حذ٠العÙقد %d"
+msgstr "حذ٠العÙقد %dØŸ"
#: editor/scene_tree_dock.cpp
msgid "Delete the root node \"%s\"?"
@@ -10677,9 +10681,8 @@ msgid "Change Type"
msgstr "تغيير النوع"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Reparent to New Node"
-msgstr "إنشاء %s جديد"
+msgstr "تعين لعقدة جديدة"
#: editor/scene_tree_dock.cpp
msgid "Make Scene Root"
@@ -10735,22 +10738,19 @@ msgstr "مسح الموروث؟ (لا تراجع!)"
#: editor/scene_tree_editor.cpp
msgid "Toggle Visible"
-msgstr "تشغيل/Ø¥Ø·ÙØ§Ø¡ الوضوحية"
+msgstr "تشغيل/Ø¥Ø·ÙØ§Ø¡ الوضوحية"
#: editor/scene_tree_editor.cpp
-#, fuzzy
msgid "Unlock Node"
-msgstr "عقدة اللقطة الواحدة"
+msgstr "إلغاء تأمين العقدة"
#: editor/scene_tree_editor.cpp
-#, fuzzy
msgid "Button Group"
-msgstr "Ø¥Ø¶Ø§ÙØ© إلي مجموعة"
+msgstr "مجموعة الأزرار"
#: editor/scene_tree_editor.cpp
-#, fuzzy
msgid "(Connecting From)"
-msgstr "خطأ ÙÙŠ الإتصال"
+msgstr "(الإتصال من)"
#: editor/scene_tree_editor.cpp
msgid "Node configuration warning:"
@@ -10845,23 +10845,20 @@ msgid "Path is not local."
msgstr "المسار ليس محلياً."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Invalid base path."
msgstr "مسار غير صالح."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "A directory with the same name exists."
-msgstr "مل٠أو مجلد مع هذا الأسم موجود Ø¨Ø§Ù„ÙØ¹Ù„."
+msgstr "يوجد ملÙ/مجلد Ø¨Ù†ÙØ³ الاسم."
#: editor/script_create_dialog.cpp
msgid "File does not exist."
msgstr "المل٠غير موجود."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Invalid extension."
-msgstr "يجب أن يستخدم صيغة صحيحة."
+msgstr "صيغة غير صالحة."
#: editor/script_create_dialog.cpp
msgid "Wrong extension chosen."
@@ -10912,33 +10909,28 @@ msgid "Invalid inherited parent name or path."
msgstr "إن اسم أو مسار الأب (الأصل parent) الموروث غير صالح."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Script path/name is valid."
-msgstr "شجرة الحركة صحيحة."
+msgstr "مسار/اسم البرنامج النصي صالح."
#: editor/script_create_dialog.cpp
msgid "Allowed: a-z, A-Z, 0-9, _ and ."
-msgstr "المسموح: a-z، A-Z ، 0-9 ، _ و ."
+msgstr "المسموح: a-z، A-Z ، 0-9 ، _ و ."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Built-in script (into scene file)."
-msgstr "عمليات مع Ù…Ù„ÙØ§Øª المشهد."
+msgstr "نص برمجي مدموج (داخل مل٠المشهد)."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Will create a new script file."
-msgstr "إنشاء مل٠كود جديد"
+msgstr "سيتم إنشاء مل٠برمجي جديد."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Will load an existing script file."
-msgstr "تحميل نسق بيوس موجود مسبقاً."
+msgstr "سيتم تحميل مل٠برمجي موجود مسبقاً."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Script file already exists."
-msgstr "التحميل التلقائي '%s' موجود اصلا!"
+msgstr "المل٠البرمجي موجود Ø¨Ø§Ù„ÙØ¹Ù„."
#: editor/script_create_dialog.cpp
msgid ""
@@ -10949,19 +10941,16 @@ msgstr ""
"تعديلها باستخدام Ù…ÙØ­Ø±Ø± خارجي."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Class Name:"
-msgstr "إسم صنÙ"
+msgstr "اسم Ø§Ù„ÙØ¦Ø©:"
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Template:"
-msgstr "مسح القالب"
+msgstr "القالب:"
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Built-in Script:"
-msgstr "ÙØªØ­ الكود"
+msgstr "مل٠النص Ø§Ù„Ù…ÙØ¯Ù…ج:"
#: editor/script_create_dialog.cpp
msgid "Attach Node Script"
@@ -10976,39 +10965,32 @@ msgid "Bytes:"
msgstr "Bytes:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Warning:"
-msgstr "تحذيرات"
+msgstr "تحذير:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Error:"
-msgstr "خطأ!"
+msgstr "خطأ:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "C++ Error"
-msgstr "خطأ ÙÙŠ نسخ"
+msgstr "خطأ ÙÙŠ C++"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "C++ Error:"
-msgstr "خطأ ÙÙŠ نسخ"
+msgstr "خطأ C++ :"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "C++ Source"
-msgstr "مورد"
+msgstr "مصدر C++"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Source:"
-msgstr "مورد"
+msgstr "مصدر:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "C++ Source:"
-msgstr "مورد"
+msgstr "مصدر C++:"
#: editor/script_editor_debugger.cpp
msgid "Stack Trace"
@@ -11019,9 +11001,8 @@ msgid "Errors"
msgstr "أخطاء"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Child process connected."
-msgstr "غير متصل"
+msgstr "العملية التابعة متصلة."
#: editor/script_editor_debugger.cpp
msgid "Copy Error"
@@ -11029,12 +11010,11 @@ msgstr "خطأ ÙÙŠ نسخ"
#: editor/script_editor_debugger.cpp
msgid "Video RAM"
-msgstr "ذاكرة الÙيديو Video RAM"
+msgstr "الذاكرة العشوائية للÙيديو"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Skip Breakpoints"
-msgstr "مسح النقاط"
+msgstr "تخطي نقاط التكسّر"
#: editor/script_editor_debugger.cpp
msgid "Inspect Previous Instance"
@@ -11081,9 +11061,8 @@ msgid "Total:"
msgstr "المجموع الكلي:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Export list to a CSV file"
-msgstr "تصدير الملÙ"
+msgstr "تصدير القائمة إلى مل٠CSV"
#: editor/script_editor_debugger.cpp
msgid "Resource Path"
@@ -11126,18 +11105,16 @@ msgid "Export measures as CSV"
msgstr "تصدير القياسات ك CSV"
#: editor/settings_config_dialog.cpp
-#, fuzzy
msgid "Erase Shortcut"
-msgstr "تخÙي٠للخارج"
+msgstr "حذ٠الاختصار"
#: editor/settings_config_dialog.cpp
msgid "Restore Shortcut"
msgstr "إعادة تعيين الاختصارات"
#: editor/settings_config_dialog.cpp
-#, fuzzy
msgid "Change Shortcut"
-msgstr "تغيير المرتكزات"
+msgstr "تغيير الاختصارات"
#: editor/settings_config_dialog.cpp
msgid "Editor Settings"
@@ -11209,19 +11186,16 @@ msgid "Change Ray Shape Length"
msgstr "تعديل طول الشكل الشعاعي"
#: modules/csg/csg_gizmos.cpp
-#, fuzzy
msgid "Change Cylinder Radius"
-msgstr "تغيير وقت الدمج"
+msgstr "تغيير نص٠قطر الاسطوانة"
#: modules/csg/csg_gizmos.cpp
-#, fuzzy
msgid "Change Cylinder Height"
-msgstr "تغيير وقت الدمج"
+msgstr "تغيير Ø§Ø±ØªÙØ§Ø¹ الاسطوانة"
#: modules/csg/csg_gizmos.cpp
-#, fuzzy
msgid "Change Torus Inner Radius"
-msgstr "تغيير المرتكزات و الهوامش"
+msgstr "تغيير نص٠قطر الدائرة الداخلي"
#: modules/csg/csg_gizmos.cpp
msgid "Change Torus Outer Radius"
@@ -11265,12 +11239,11 @@ msgstr "مكتبة GDNativeLibrary"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Enabled GDNative Singleton"
-msgstr "تمكين نمط البرمجة Singleton ل٠GDNative"
+msgstr "تمكين نمط البرمجة Singleton لـ GDNative"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
-#, fuzzy
msgid "Disabled GDNative Singleton"
-msgstr "تعطيل دوار التحديث"
+msgstr "تعطيل نمط البرمجة Singleton لـ GDNative"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Library"
@@ -11285,17 +11258,16 @@ msgid "GDNative"
msgstr "GDNative"
#: modules/gdscript/gdscript_functions.cpp
-#, fuzzy
msgid "Step argument is zero!"
-msgstr "الخطوة (المتغيرة المدخلة/argument) تساوي ØµÙØ± !"
+msgstr "معامل الخطوة تساوي ØµÙØ±!"
#: modules/gdscript/gdscript_functions.cpp
msgid "Not a script with an instance"
-msgstr "ليس كود مع نموذج"
+msgstr "ليس نص برمجي مع نموذج"
#: modules/gdscript/gdscript_functions.cpp
msgid "Not based on a script"
-msgstr "لا تستند الى Ø´ÙØ±Ø© مصدرية"
+msgstr "لا تستند الى نص برمجي"
#: modules/gdscript/gdscript_functions.cpp
msgid "Not based on a resource file"
@@ -11303,42 +11275,35 @@ msgstr "لا تستند على مل٠مورد"
#: modules/gdscript/gdscript_functions.cpp
msgid "Invalid instance dictionary format (missing @path)"
-msgstr ""
-"instance dictionary format نموذج الشكل القاموسي غير صالح - المسار Ù…Ùقود"
+msgstr "نموذج الشكل القاموسي غير صالح (@المسار Ù…Ùقود)"
#: modules/gdscript/gdscript_functions.cpp
msgid "Invalid instance dictionary format (can't load script at @path)"
-msgstr ""
-"instance dictionary format نموذج الشكل القاموسي غير صالح - لا يمكن تحميل "
-"السكريبت من المسار"
+msgstr "نموذج الشكل القاموسي غير صالح (لا يمكن تحميل النص البرمجي من @المسار)"
#: modules/gdscript/gdscript_functions.cpp
msgid "Invalid instance dictionary format (invalid script at @path)"
-msgstr ""
-"instance dictionary format نموذج الشكل القاموسي غير صالح - السكريبت ÙÙŠ "
-"المسار غير صالح"
+msgstr "نموذج الشكل القاموسي غير صالح ( النص البرمجي غير صالح ÙÙŠ @المسار)"
#: modules/gdscript/gdscript_functions.cpp
msgid "Invalid instance dictionary (invalid subclasses)"
-msgstr "مجسّد القاموس غير صالح (Ø£ØµÙ†Ø§Ù ÙØ±Ø¹ÙŠØ© غير صالحة)"
+msgstr "نموذج القاموس غير صالح (Ø£ØµÙ†Ø§Ù ÙØ±Ø¹ÙŠØ© غير صالحة)"
#: modules/gdscript/gdscript_functions.cpp
msgid "Object can't provide a length."
-msgstr "لا يمكن للكائن Object أن يمنح طولاً."
+msgstr "لا يمكن للكائن أن يمنح طولاً."
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Next Plane"
msgstr "التبويب التالي"
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Previous Plane"
msgstr "التبويب السابق"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Plane:"
-msgstr "المستوى:"
+msgstr "التبويت:"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Next Floor"
@@ -11357,14 +11322,12 @@ msgid "GridMap Delete Selection"
msgstr "خريطة الشبكة GridMap Ù„Ø­Ø°Ù Ø§Ù„Ù…ÙØ®ØªØ§Ø±"
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "GridMap Fill Selection"
-msgstr "ÙƒÙÙ„ Ø§Ù„Ù…ÙØ­Ø¯Ø¯"
+msgstr "تحديد الملئ خريطة-الشبكة"
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "GridMap Paste Selection"
-msgstr "ÙƒÙÙ„ Ø§Ù„Ù…ÙØ­Ø¯Ø¯"
+msgstr "تحديد اللصق خريطة-الشبكة"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "GridMap Paint"
@@ -11431,9 +11394,8 @@ msgid "Cursor Clear Rotation"
msgstr "مسح تدوير المؤشر"
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Paste Selects"
-msgstr "ÙƒÙÙ„ Ø§Ù„Ù…ÙØ­Ø¯Ø¯"
+msgstr "تحديد اللصق"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Clear Selection"
@@ -11452,9 +11414,8 @@ msgid "Pick Distance:"
msgstr "اختر Ø§Ù„Ù…Ø³Ø§ÙØ©:"
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Filter meshes"
-msgstr "وضع Ø§Ù„Ù…ÙØµÙÙŠ:"
+msgstr "تنقية المجسمات"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Give a MeshLibrary resource to this GridMap to use its meshes."
@@ -11561,7 +11522,7 @@ msgstr "عثر على تسلسل بت ولكن ليس العقدة ÙÙŠ المك
#: modules/visual_script/visual_script.cpp
msgid "Stack overflow with stack depth: "
-msgstr ""
+msgstr "حدوث تجاوز للتكدس ( Stack overflow) مع عمق التكدس: "
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Signal Arguments"
@@ -11584,42 +11545,36 @@ msgid "Set Variable Type"
msgstr "تحيد نوع المتغير"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Input Port"
-msgstr "أض٠مدخله"
+msgstr "Ø£Ø¶Ù Ù…Ù†ÙØ° أدخال"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Output Port"
-msgstr "أض٠مدخله"
+msgstr "Ø£Ø¶Ù Ù…Ù†ÙØ° إخراج"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Override an existing built-in function."
-msgstr "إسم غير صالح، يجب أن لا يتصادم مع الأسماء المبنية تلقائياً الموجودة."
+msgstr "تجاوز لدالة Ù…ÙØ¯Ù…جة موجودة مسبقًا."
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Create a new function."
-msgstr "إنشاء %s جديد"
+msgstr "إنشاء دالة جديدة."
#: modules/visual_script/visual_script_editor.cpp
msgid "Variables:"
msgstr "المتغيرات:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Create a new variable."
-msgstr "إنشاء %s جديد"
+msgstr "إنشاء متغير جديد."
#: modules/visual_script/visual_script_editor.cpp
msgid "Signals:"
msgstr "الإشارات:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Create a new signal."
-msgstr "أنشئ شكل جديد من لا شئ."
+msgstr "إنشاء إشارة جديدة."
#: modules/visual_script/visual_script_editor.cpp
msgid "Name is not a valid identifier:"
@@ -11646,9 +11601,8 @@ msgid "Add Function"
msgstr "Ø¥Ø¶Ø§ÙØ© ÙˆØ¸ÙŠÙØ© برمجية"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Delete input port"
-msgstr "مسح النقطة"
+msgstr "مسح Ù…Ù†ÙØ° إدخال"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Variable"
@@ -11659,14 +11613,12 @@ msgid "Add Signal"
msgstr "Ø¥Ø¶Ø§ÙØ© إشارة"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Remove Input Port"
-msgstr "مسح النقطة"
+msgstr "Ø­Ø°Ù Ù…Ù†ÙØ° إدخال"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Remove Output Port"
-msgstr "مسح النقطة"
+msgstr "Ø­Ø°Ù Ù…Ù†ÙØ° إخراج"
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Expression"
@@ -11750,19 +11702,16 @@ msgid "Connect Nodes"
msgstr "وصل العÙقد"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Disconnect Nodes"
-msgstr "غير متصل"
+msgstr "عÙقد غير متصلة"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Connect Node Data"
-msgstr "صلها بالعقدة:"
+msgstr "ربط بيانات العقدة"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Connect Node Sequence"
-msgstr "صلها بالعقدة:"
+msgstr "ربط تسلسل العقدة"
#: modules/visual_script/visual_script_editor.cpp
msgid "Script already has function '%s'"
@@ -11773,9 +11722,8 @@ msgid "Change Input Value"
msgstr "تعديل قيمة الإدخال"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Resize Comment"
-msgstr "تعديل العنصر القماشي"
+msgstr "تغيير حجم التعليق"
#: modules/visual_script/visual_script_editor.cpp
msgid "Can't copy the function node."
@@ -11807,9 +11755,8 @@ msgid "Try to only have one sequence input in selection."
msgstr "حاول أن يكون لديك تسلسل إدخال واحد من Ø§Ù„Ù…ÙØ®ØªØ§Ø±."
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Create Function"
-msgstr "عمل اشتراك"
+msgstr "إنشاء دالة"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove Function"
@@ -11832,33 +11779,28 @@ msgid "Editing Signal:"
msgstr "تحرير الإشارة:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Make Tool:"
-msgstr "أنشئ عظام"
+msgstr "عمل أداة:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Members:"
msgstr "الأعضاء:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Change Base Type:"
-msgstr "غير نوع %s"
+msgstr "تغيير اساس النوع:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Nodes..."
-msgstr "Ø¥Ø¶Ø§ÙØ© %s..."
+msgstr "Ø¥Ø¶Ø§ÙØ© عÙقد..."
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Function..."
-msgstr "مسح المهمة"
+msgstr "Ø¥Ø¶Ø§ÙØ© دالة…"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "function_name"
-msgstr "الإعدادات:"
+msgstr "أسم_الدالة"
#: modules/visual_script/visual_script_editor.cpp
msgid "Select or create a function to edit its graph."
@@ -11881,19 +11823,16 @@ msgid "Cut Nodes"
msgstr "قص العÙقد"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Make Function"
-msgstr "مسح المهمة"
+msgstr "عمل دالة"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Refresh Graph"
-msgstr "تحديث"
+msgstr "تحديث الرسم البياني"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Edit Member"
-msgstr "الأعضاء"
+msgstr "تعديل العضو"
#: modules/visual_script/visual_script_flow_control.cpp
msgid "Input type not iterable: "
@@ -11941,7 +11880,7 @@ msgstr "لم يتم إيجاد (Ù…ÙØ­Ø¯Ø¯ Ø§Ù„Ù…ÙØªØºÙŠØ±) VariableSet ÙÙŠ ا
#: modules/visual_script/visual_script_nodes.cpp
msgid "Custom node has no _step() method, can't process graph."
-msgstr "العقدة المخصصة لا تحتوي طريقة ()step_ ، لا يمكن معالجة المخطوط."
+msgstr "العقدة المخصصة لا تحتوي طريقة ()step_ ، لا يمكن معالجة الشكل البياني."
#: modules/visual_script/visual_script_nodes.cpp
msgid ""
@@ -11952,9 +11891,8 @@ msgstr ""
"(خطأ)."
#: modules/visual_script/visual_script_property_selector.cpp
-#, fuzzy
msgid "Search VisualScript"
-msgstr "إخلاء الكود"
+msgstr "بحث VisualScript"
#: modules/visual_script/visual_script_property_selector.cpp
msgid "Get %s"
@@ -12009,11 +11947,8 @@ msgstr ""
"الموضوعة Ø³Ù„ÙØ§Ù‹."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Release keystore incorrectly configured in the export preset."
-msgstr ""
-"Ù…Ùنقح أخطاء Ù…ÙØªØ§Ø­ المتجر keystore غير Ù…Ùهيئ ÙÙŠ إعدادت Ø§Ù„Ù…ÙØ­Ø±Ø± أو ÙÙŠ الإعدادات "
-"الموضوعة Ø³Ù„ÙØ§Ù‹."
+msgstr "تحرر مخزن Ø§Ù„Ù…ÙØ§ØªÙŠØ­ غير Ù…Ùهيئ بشكل صحيح ÙÙŠ إعدادت المسبقة للتصدير."
#: platform/android/export/export.cpp
msgid "Custom build requires a valid Android SDK path in Editor Settings."
@@ -12045,26 +11980,34 @@ msgid ""
"Invalid \"GodotPaymentV3\" module included in the \"android/modules\" "
"project setting (changed in Godot 3.2.2).\n"
msgstr ""
+"وحدة \"GodotPaymentV3\" المضمنة ÙÙŠ إعدادات المشروع \"android / modules\" غير "
+"صالحة (تم تغييره ÙÙŠ Godot 3.2.2).\n"
#: platform/android/export/export.cpp
msgid "\"Use Custom Build\" must be enabled to use the plugins."
-msgstr ""
+msgstr "يجب ØªÙØ¹ÙŠÙ„ \"Use Custom Build\" لإستخدام Ø§Ù„Ø¥Ø¶Ø§ÙØ§Øª."
#: platform/android/export/export.cpp
msgid ""
"\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR"
"\"."
msgstr ""
+"\"Degrees Of Freedom\" تكون صالحة Ùقط عندما يكون وضع الـ \"Xr Mode\"هو "
+"\"Oculus Mobile VR\"."
#: platform/android/export/export.cpp
msgid ""
"\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
+"\"Hand Tracking\" تكون صالحة Ùقط عندما يكون وضع الـ \"Xr Mode\"هو \"Oculus "
+"Mobile VR\"."
#: platform/android/export/export.cpp
msgid ""
"\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
+"\"Focus Awareness\" تكون صالحة Ùقط عندما يكون وضع الـ \"Xr Mode\"هو \"Oculus "
+"Mobile VR\"."
#: platform/android/export/export.cpp
msgid ""
@@ -12213,13 +12156,12 @@ msgid "Invalid splash screen image dimensions (should be 620x300)."
msgstr "أبعاد شاشة البداية غير صالحة (ينبغي أن تكون 620×300)."
#: scene/2d/animated_sprite.cpp
-#, fuzzy
msgid ""
"A SpriteFrames resource must be created or set in the \"Frames\" property in "
"order for AnimatedSprite to display frames."
msgstr ""
-"ليتم إظهار الأطر (اللقطات) ÙÙŠ الAnimatedSprite (النقوش المتحركة), يجب تكوين "
-"مصدر لها من نوع SpriteFrames و ضبط خاصية الFrames (الأطر) بها."
+"ليتم إظهار الإطارات ÙÙŠ الAnimatedSprite (النقوش المتحركة), يجب تكوين مصدر "
+"لها من نوع SpriteFrames و ضبط خاصية الFrames (الأطر) بها."
#: scene/2d/canvas_modulate.cpp
msgid ""
@@ -12255,7 +12197,9 @@ msgstr ""
#: scene/2d/collision_polygon_2d.cpp
msgid "An empty CollisionPolygon2D has no effect on collision."
-msgstr "Ù…ÙØ¶Ù„ع تصادم ثنائي الأبعاد ÙØ§Ø±Øº ليس له أي تأثير على التصادم."
+msgstr ""
+"Ù…ÙØ¶Ù„ع تصادم ثنائي الأبعاد (CollisionPolygon2D) Ø§Ù„ÙØ§Ø±Øº ليس له أي تأثير على "
+"التصادم."
#: scene/2d/collision_shape_2d.cpp
msgid ""
@@ -12263,32 +12207,37 @@ msgid ""
"CollisionObject2D derived node. Please only use it as a child of Area2D, "
"StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."
msgstr ""
-"يعمل Ù…ÙØ¶Ù„ع التصادم ثنائي الأبعاد CollisionPolygon2D Ùقط كشكل تصادمي لكل العÙقد "
-"المشتقة من الكائن التصادمي ثنائي الأبعاد CollisionObject2D. من ÙØ¶Ù„Ùƒ استخدمه "
-"Ùقط لكل أبناء الحيز ثنائي الأبعاد Area2DØŒ الجسم السكوني ثنائي الأبعاد "
-"StaticBody2D و الجسم الجامد ثنائي الأبعاد RigidBody2D، والجسم المتحرك ثنائي "
-"الأبعاد KinematicBody2D إلخ.. لكي تمنح كل منهم شكلاً."
+"يعمل جسم-تصادم-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯ (CollisionPolygon2D) Ùقط كشكل تصادمي لكل العÙقد "
+"المشتقة من الكائن التصادمي ثنائي الأبعاد (CollisionObject2D). من ÙØ¶Ù„Ùƒ "
+"استخدمه Ùقط لكل أبناء الحيز-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯ (Area2D)ØŒ الجسم-الثابت-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯ "
+"(StaticBody2D) Ùˆ الجسم-الصلب-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯ (RigidBody2D)ØŒ والجسم-المتحرك-ثنائي-"
+"Ø§Ù„Ø¨ÙØ¹Ø¯ (KinematicBody2D) إلخ.. لكي تمنح كل منهم شكلاً."
#: scene/2d/collision_shape_2d.cpp
msgid ""
"A shape must be provided for CollisionShape2D to function. Please create a "
"shape resource for it!"
msgstr ""
-"يجب تزويد ال CollisionShape2D بإحدى الأشكال (من نوع Shape2D) لتعمل بالشكل "
-"المطلوب. الرجاء تكوين و ضبط الشكل لها اولا!"
+"يجب تزويد جسم-تصادم-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯ (CollisionShape2D) بإحدى الأشكال (من نوع "
+"Shape2D) لتعمل بالشكل المطلوب. الرجاء تكوين و ضبط الشكل لها اولا!"
#: scene/2d/collision_shape_2d.cpp
msgid ""
"Polygon-based shapes are not meant be used nor edited directly through the "
"CollisionShape2D node. Please use the CollisionPolygon2D node instead."
msgstr ""
+"الأشكال المستندة إلى المضلع (Polygon-based shapes) لا تعني انك قادر على "
+"استخدامها او تعديلها بشكل مباشر من خلال عقدة جسم-تصادم-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯ "
+"(CollisionShape2D). الرجاء استخدام عقدة مضلع-تصادم-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯ "
+"(CollisionPolygon2D) بدلاً من ذلك."
#: scene/2d/cpu_particles_2d.cpp
msgid ""
"CPUParticles2D animation requires the usage of a CanvasItemMaterial with "
"\"Particles Animation\" enabled."
msgstr ""
-"تتطلب الرسوم المتحركة CPUParticles2D استخدام CanvasItemMaterial مع تمكين "
+"تتطلب الرسوم المتحركة للجسيمات-وحدة-المعالجة-المركزية-ثنائية-الأبعاد "
+"(CPUParticles2D) استخدام لوحة-مادة-العنصر (CanvasItemMaterial) مع ØªÙØ¹ÙŠÙ„"
"\"الرسوم المتحركة للجزيئات\"."
#: scene/2d/light_2d.cpp
@@ -12301,27 +12250,34 @@ msgstr "يجب توريد نقش بهيئة الضوء لخاصية \"النقش
msgid ""
"An occluder polygon must be set (or drawn) for this occluder to take effect."
msgstr ""
+"Ø§Ù„Ù…ÙØ¶Ù„ع Ø§Ù„Ù…ÙØºÙ„Ù‚(occluder polygon) يجب تعينه (او رسمه) ليأخذ هذا الغَلق تأثيره."
#: scene/2d/light_occluder_2d.cpp
msgid "The occluder polygon for this occluder is empty. Please draw a polygon."
-msgstr ""
+msgstr "Ø§Ù„Ù…ÙØ¶Ù„ع Ø§Ù„Ù…ÙØºÙ„Ù‚ لهذا الغَلق ÙØ§Ø±Øº. الرجاء رسم Ù…ÙØ¶Ù„ع."
#: scene/2d/navigation_polygon.cpp
msgid ""
"A NavigationPolygon resource must be set or created for this node to work. "
"Please set a property or draw a polygon."
msgstr ""
+"يجب تعيين مصدر Ù…ÙØ¶Ù„ع-التنقل (NavigationPolygon) أو إنشاؤه حتى تعمل هذه "
+"العقدة. ÙŠÙØ±Ø¬Ù‰ تعيين خاصية أو رسم مضلع."
#: scene/2d/navigation_polygon.cpp
msgid ""
"NavigationPolygonInstance must be a child or grandchild to a Navigation2D "
"node. It only provides navigation data."
msgstr ""
+"يجب أن يكون نموذج-المضلع-المتنقل (NavigationPolygonInstance) تابعًا أو Ø­Ùيدًا "
+"لعقدة التنقل-ثنائي-الأبعاد (Navigation2D). انه Ùقط ÙŠÙˆÙØ± بيانات التنقل."
#: scene/2d/parallax_layer.cpp
msgid ""
"ParallaxLayer node only works when set as child of a ParallaxBackground node."
msgstr ""
+"تعمل عقدة طبقة-المنظهر (ParallaxLayer) Ùقط عند تعيينها كعقدة تابعة لعقدة "
+"خلÙية-المنظر ParallaxBackground."
#: scene/2d/particles_2d.cpp
msgid ""
@@ -12329,22 +12285,31 @@ msgid ""
"Use the CPUParticles2D node instead. You can use the \"Convert to "
"CPUParticles\" option for this purpose."
msgstr ""
+"لا يدعم برنامج تشغيل الÙيديو GLES2 الجسيمات القائمة على وحدة معالجة الرسومات "
+"(GPU-based particles).\n"
+"استخدم عقدة جسيمات-وحدة-المعالجة-المركزية-ثنائية-Ø§Ù„Ø¨ÙØ¹Ø¯ (CPUParticles2D) بدلاً "
+"من ذلك. يمكنك استخدام خيار \"التحويل إلى CPUParticles\" لهذا الغرض."
#: scene/2d/particles_2d.cpp scene/3d/particles.cpp
msgid ""
"A material to process the particles is not assigned, so no behavior is "
"imprinted."
msgstr ""
+"لا يوجد مادة (material) لمعالجة الجسيمات ، لذلك لا يتم طبع او عمل أي سلوك."
#: scene/2d/particles_2d.cpp
msgid ""
"Particles2D animation requires the usage of a CanvasItemMaterial with "
"\"Particles Animation\" enabled."
msgstr ""
+"تتطلب الرسوم المتحركة للجسيمات-ثنائية-Ø§Ù„Ø¨ÙØ¹Ø¯ (Particles2D) استخدام لوحة-مادة-"
+"العنصر (CanvasItemMaterial) مع تمكين \"الرسوم المتحركة للجسيمات\"."
#: scene/2d/path_2d.cpp
msgid "PathFollow2D only works when set as a child of a Path2D node."
msgstr ""
+"لا يعمل اتباع-المسار-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯ (PathFollow2D) إلا عند جعل عقدة مسار-ثنائي-"
+"Ø§Ù„Ø¨ÙØ¹Ø¯ (Path2D) تابعًا له."
#: scene/2d/physics_body_2d.cpp
msgid ""
@@ -12352,10 +12317,14 @@ msgid ""
"by the physics engine when running.\n"
"Change the size in children collision shapes instead."
msgstr ""
+"تغييرات الحجم للجسم-صلب-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯ (RigidBody2D) (ÙÙŠ أوضاع الشخصيات أو "
+"الأوضاع الصلبة) سيتم تجاوزها بواسطة محرك الÙيزياء عند التشغيل.\n"
+"قم بتغيير الحجم ÙÙŠ أشكال تصادم التابعين له بدلاً من ذلك."
#: scene/2d/remote_transform_2d.cpp
msgid "Path property must point to a valid Node2D node to work."
msgstr ""
+"يجب أن تشير خاصية المسار إلى عÙقدة-ثنائية-Ø§Ù„Ø¨ÙØ¹Ø¯ (Node2D) صالحة لكي تعمل."
#: scene/2d/skeleton_2d.cpp
msgid "This Bone2D chain should end at a Skeleton2D node."
@@ -12366,11 +12335,15 @@ msgstr ""
#: scene/2d/skeleton_2d.cpp
msgid "A Bone2D only works with a Skeleton2D or another Bone2D as parent node."
msgstr ""
+"يعمل عظم-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯ (Bone2D) Ùقط مع هيكلية-ثنائية-Ø§Ù„Ø¨ÙØ¹Ø¯ (Skeleton2D) أو "
+"Bone2D آخر كعقدة رئيسية."
#: scene/2d/skeleton_2d.cpp
msgid ""
"This bone lacks a proper REST pose. Go to the Skeleton2D node and set one."
msgstr ""
+"هذا العظم ÙŠÙØªÙ‚ر إلى وضع الراحة المناسب. انتقل إلى عقدة هيكلية ثنائية "
+"Ø§Ù„Ø¨ÙØ¹Ø¯(Skeleton2D) وقم بتعيين واحدة."
#: scene/2d/tile_map.cpp
msgid ""
@@ -12378,40 +12351,56 @@ msgid ""
"to. Please use it as a child of Area2D, StaticBody2D, RigidBody2D, "
"KinematicBody2D, etc. to give them a shape."
msgstr ""
+"يحتاج خريطة-البلاط (TileMap) مع ØªÙØ¹ÙŠÙ„ خاصية إستخدام الأصل (Use Parent) إلى "
+"ان يكون تابعًا لكائن-تصادمي-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯ (CollisionObject2D) لإعطاء الأشكال. "
+"يرجى استخدامه كتابع لحيز-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯(ÙArea2D)ØŒ جسم-ثابت-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯ "
+"(StaticBody2D)ØŒ جسم-صلب-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯ (RigidBody2D)ØŒ أو جسم-متحرك-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯ "
+"(KinematicBody2D)، وما إلى ذلك لمنحهم شكلاً."
#: scene/2d/visibility_notifier_2d.cpp
msgid ""
"VisibilityEnabler2D works best when used with the edited scene root directly "
"as parent."
msgstr ""
+"يعمل Ù…ÙÙ…ÙŽÙƒÙÙ†-الرؤية-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯ (VisibilityEnabler2D) بشكل Ø£ÙØ¶Ù„ عند استخدامه مع "
+"المشهد الرئيس الذي تم تحريره مباشرةً باعتباره الأصل."
#: scene/3d/arvr_nodes.cpp
msgid "ARVRCamera must have an ARVROrigin node as its parent."
-msgstr ""
+msgstr "يجب أن تحتوي ARVRCamera على عقدة ARVROrigin كأصل لها."
#: scene/3d/arvr_nodes.cpp
msgid "ARVRController must have an ARVROrigin node as its parent."
-msgstr ""
+msgstr "يجب أن تحتوي ARVRController على عقدة ARVROrigin كأصل لها."
#: scene/3d/arvr_nodes.cpp
msgid ""
"The controller ID must not be 0 or this controller won't be bound to an "
"actual controller."
msgstr ""
+"يجب ألا يكون معر٠وحدة التحكم تساوي 0 أو لن تكون وحدة التحكم هذه مقيدة بوحدة "
+"تحكم ÙØ¹Ù„ية."
#: scene/3d/arvr_nodes.cpp
msgid "ARVRAnchor must have an ARVROrigin node as its parent."
-msgstr ""
+msgstr "يجب أن يحتوي ARVRController على عقدة ARVROrigin كأصل له."
#: scene/3d/arvr_nodes.cpp
msgid ""
"The anchor ID must not be 0 or this anchor won't be bound to an actual "
"anchor."
msgstr ""
+"يجب ألا يكون معر٠الإرتكاز (The anchor) يساوي 0 أو لن يكون هذا الإرتكاز مقيد "
+"بإرتكاز ÙÙØ¹Ù„ÙŠ."
#: scene/3d/arvr_nodes.cpp
msgid "ARVROrigin requires an ARVRCamera child node."
msgstr ""
+"يحتاج خريطة-البلاط (TileMap) مع ØªÙØ¹ÙŠÙ„ خاصية إستخدام الأصل (Use Parent) إلى "
+"ان يكون تابعًا لكائن-تصادمي-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯ (CollisionObject2D) لإعطاء الأشكال. "
+"يرجى استخدامه كتابع لحيز-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯(ÙArea2D)ØŒ جسم-ثابت-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯ "
+"(StaticBody2D)ØŒ جسم-صلب-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯ (RigidBody2D)ØŒ أو جسم-متحرك-ثنائي-Ø§Ù„Ø¨ÙØ¹Ø¯ "
+"(KinematicBody2D)، وما إلى ذلك لمنحهم شكلاً."
#: scene/3d/baked_lightmap.cpp
msgid "%d%%"
@@ -12423,19 +12412,19 @@ msgstr "(الوقت المتبقي: %d:%02d ثانية)"
#: scene/3d/baked_lightmap.cpp
msgid "Plotting Meshes: "
-msgstr ""
+msgstr "تخطيط المجسمات: "
#: scene/3d/baked_lightmap.cpp
msgid "Plotting Lights:"
-msgstr ""
+msgstr "تخطيط الإضاءات:"
#: scene/3d/baked_lightmap.cpp scene/3d/gi_probe.cpp
msgid "Finishing Plot"
-msgstr ""
+msgstr "الانتهاء من التخطيط"
#: scene/3d/baked_lightmap.cpp
msgid "Lighting Meshes: "
-msgstr ""
+msgstr "إضاءة المجسمات: "
#: scene/3d/collision_object.cpp
msgid ""
@@ -12443,6 +12432,8 @@ msgid ""
"Consider adding a CollisionShape or CollisionPolygon as a child to define "
"its shape."
msgstr ""
+"هذه العقدة ليس لها شكل، لذلك لا يمكن أن تصطدم أو ØªØªÙØ§Ø¹Ù„ مع الكائنات الأخرى.\n"
+"ضع ÙÙŠ الإعتبار Ø¥Ø¶Ø§ÙØ© شكل تصادم أو مضلع تصادم كتابع لتعري٠شكله."
#: scene/3d/collision_polygon.cpp
msgid ""
@@ -12450,6 +12441,10 @@ msgid ""
"CollisionObject derived node. Please only use it as a child of Area, "
"StaticBody, RigidBody, KinematicBody, etc. to give them a shape."
msgstr ""
+"يعمل مضلع التصادم (CollisionPolygon) Ùقط على توÙير شكل تصادم لعقدة كائن "
+"التصادم (CollisionObject) المشتقة. ÙŠÙØ±Ø¬Ù‰ استخدامه Ùقط كتابع لحيز (Area)ØŒ جسم "
+"ثابت (StaticBody)، جسم صلب (StaticBody)، أو جسم حركي (KinematicBody)، وما "
+"إلى ذلك لمنحهم شكلاً."
#: scene/3d/collision_polygon.cpp
msgid "An empty CollisionPolygon has no effect on collision."
@@ -12461,46 +12456,58 @@ msgid ""
"derived node. Please only use it as a child of Area, StaticBody, RigidBody, "
"KinematicBody, etc. to give them a shape."
msgstr ""
+"يعمل شكل التصادم (CollisionPolygon) Ùقط على توÙير شكل تصادم لعقدة كائن "
+"التصادم (CollisionObject) المشتقة. ÙŠÙØ±Ø¬Ù‰ استخدامه Ùقط كتابع لحيز (Area)ØŒ جسم "
+"ثابت (StaticBody)، جسم صلب (StaticBody)، أو جسم حركي (KinematicBody)، وما "
+"إلى ذلك لمنحهم شكلاً."
#: scene/3d/collision_shape.cpp
-#, fuzzy
msgid ""
"A shape must be provided for CollisionShape to function. Please create a "
"shape resource for it."
msgstr ""
-"يجب تزويد ال CollisionShape2D بإحدى الأشكال (من نوع Shape2D) لتعمل بالشكل "
-"المطلوب. الرجاء تكوين و ضبط الشكل لها اولا!"
+"يجب توÙير شكل لـ CollisionShape2D بإحدى الأشكال (من نوع Shape2D) لتعمل "
+"بالشكل المطلوب. الرجاء تكوين و ضبط الشكل لها."
#: scene/3d/collision_shape.cpp
msgid ""
"Plane shapes don't work well and will be removed in future versions. Please "
"don't use them."
msgstr ""
+"لا تعمل أشكال التبويت (Plane shapes) بشكل جيد وسيتم إزالتها ÙÙŠ الإصدارات "
+"المستقبلية. من ÙØ¶Ù„Ùƒ لا تستخدمها."
#: scene/3d/collision_shape.cpp
msgid ""
"ConcavePolygonShape doesn't support RigidBody in another mode than static."
msgstr ""
+"الشكل المضلع المÙقعر (ConcavePolygonShape) لا يدعم الجسم الصلب (RigidBody) ÙÙŠ "
+"أي وضع غير الوضع الثابت."
#: scene/3d/cpu_particles.cpp
msgid "Nothing is visible because no mesh has been assigned."
-msgstr ""
+msgstr "لا شيء مرئي لأنه لم يتم تعيين أي مجسم."
#: scene/3d/cpu_particles.cpp
msgid ""
"CPUParticles animation requires the usage of a SpatialMaterial whose "
"Billboard Mode is set to \"Particle Billboard\"."
msgstr ""
+"تتطلب الرسوم المتحركة لجسيمات وحدة المعالجة المركزية( CPUParticles) استخدام "
+"مادة مكانية (SpatialMaterial) التي تم ضبط وضع اللوحة (Billboard Mode) الخاص "
+"بها على \"لوحة الجسيمات\"."
#: scene/3d/gi_probe.cpp
msgid "Plotting Meshes"
-msgstr ""
+msgstr "تخطيط المجسمات"
#: scene/3d/gi_probe.cpp
msgid ""
"GIProbes are not supported by the GLES2 video driver.\n"
"Use a BakedLightmap instead."
msgstr ""
+"GIProbes لا يدعم برنامج تشغيل الÙيديو GLES2.\n"
+"استخدم BakedLightmap بدلاً من ذلك."
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
@@ -12509,12 +12516,15 @@ msgstr "بقعة الضوء بزاوية أكبر من 90 درجة لا يمكن
#: scene/3d/navigation_mesh.cpp
msgid "A NavigationMesh resource must be set or created for this node to work."
msgstr ""
+"يجب تعيين مصدر مجسم-التنقل (NavigationMesh) أو إنشاؤه حتى تعمل هذه العقدة."
#: scene/3d/navigation_mesh.cpp
msgid ""
"NavigationMeshInstance must be a child or grandchild to a Navigation node. "
"It only provides navigation data."
msgstr ""
+"يجب أن يكون نموذج-مجسم-التنقل (NavigationMeshInstance) تابعًا أو Ø­Ùيدًا لعقدة "
+"التنقل (Navigation node). انه ÙŠÙˆÙØ± Ùقط بيانات التنقل."
#: scene/3d/particles.cpp
msgid ""
@@ -12522,17 +12532,23 @@ msgid ""
"Use the CPUParticles node instead. You can use the \"Convert to CPUParticles"
"\" option for this purpose."
msgstr ""
+"الجسيمات القائمة على وحدة معالجة الرسومات (GPU-based particles) لا تدعم "
+"برنامج تشغيل الÙيديو GLES2 .\n"
+"استخدم عقدة CPUParticles بدلاً من ذلك. يمكنك استخدام خيار \"التحويل إلى "
+"CPUParticles\" لهذا الغرض."
#: scene/3d/particles.cpp
msgid ""
"Nothing is visible because meshes have not been assigned to draw passes."
-msgstr ""
+msgstr "لا يوجد شيء مرئي لأن المجسمات لم يتم تعيين لها رسم التمريرات."
#: scene/3d/particles.cpp
msgid ""
"Particles animation requires the usage of a SpatialMaterial whose Billboard "
"Mode is set to \"Particle Billboard\"."
msgstr ""
+"تتطلب الرسوم المتحركة للجسيمات استخدام مادة مكانية (SpatialMaterial) التي تم "
+"ضبط وضع اللوحة (Billboard Mode) الخاص بها على \"لوحة الجسيمات\"."
#: scene/3d/path.cpp
msgid "PathFollow only works when set as a child of a Path node."
@@ -12543,6 +12559,8 @@ msgid ""
"PathFollow's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its "
"parent Path's Curve resource."
msgstr ""
+"يتطلب ROTATION_ORIENTED الخاص بأتباع-المسار (PathFollow) تمكين \"Up Vector\" "
+"ÙÙŠ مصدر منحنى مسار الأصل (Parent Path's)."
#: scene/3d/physics_body.cpp
msgid ""
@@ -12550,16 +12568,21 @@ msgid ""
"by the physics engine when running.\n"
"Change the size in children collision shapes instead."
msgstr ""
+"تغير حجم الجسم الصلب (RigidBody) (ÙÙŠ الشخصية أو الأوضاع الصلبة) سيتم تجاوزها "
+"بواسطة محرك الÙيزياء عند التشغيل.\n"
+"قم بتغيير الحجم ÙÙŠ أشكال تصادم الأتباع (Children) بدلاً من ذلك."
#: scene/3d/remote_transform.cpp
msgid ""
"The \"Remote Path\" property must point to a valid Spatial or Spatial-"
"derived node to work."
msgstr ""
+"يجب أن تشير خاصية \"المسار البعيد\" إلى عقدة مكانية أو مشتقة مكانية صالحة "
+"لكي تعمل."
#: scene/3d/soft_body.cpp
msgid "This body will be ignored until you set a mesh."
-msgstr "سيتم تجاهل هذا الجسم حتى تضع تحدد سطحاً mesh."
+msgstr "سيتم تجاهل هذا الجسم حتى تضع تحدد له مجسمًا."
#: scene/3d/soft_body.cpp
msgid ""
@@ -12567,42 +12590,52 @@ msgid ""
"running.\n"
"Change the size in children collision shapes instead."
msgstr ""
+"تغير حجم الجسم الناعم (SoftBody) سيتم تجاوزها بواسطة محرك الÙيزياء عند "
+"التشغيل.\n"
+"قم بتغيير الحجم ÙÙŠ أشكال تصادم الأتباع (Children) بدلاً من ذلك."
#: scene/3d/sprite_3d.cpp
-#, fuzzy
msgid ""
"A SpriteFrames resource must be created or set in the \"Frames\" property in "
"order for AnimatedSprite3D to display frames."
msgstr ""
-"ليتم إظهار الأطر (اللقطات) ÙÙŠ الAnimatedSprite (النقوش المتحركة), يجب تكوين "
-"مصدر لها من نوع SpriteFrames و ضبط خاصية الFrames (الأطر) بها."
+"يجب إنشاء مصدر إطارات الرسم (SpriteFrames) أو تعيينه ÙÙŠ خاصية \"الإطارات\" "
+"حتى يتمكن الرسوم المتحركة للرسم ثلاثي Ø§Ù„ÙØ¹Ø¯ (AnimatedSprite3D) من عرض "
+"الإطارات."
#: scene/3d/vehicle_body.cpp
msgid ""
"VehicleWheel serves to provide a wheel system to a VehicleBody. Please use "
"it as a child of a VehicleBody."
msgstr ""
+"تعمل عجلة المركبة (VehicleWheel) على توÙير نظام عجلات لجسم "
+"المركبة(VehicleBody). يرجى استخدامه كتابع لجسم المركبة."
#: scene/3d/world_environment.cpp
msgid ""
"WorldEnvironment requires its \"Environment\" property to contain an "
"Environment to have a visible effect."
msgstr ""
+"تتطلب بيئة-العالم (WorldEnvironment) خاصية\"البيئة\" الخاصة بها لاحتواء بيئة "
+"ليكون لها تأثير مرئي."
#: scene/3d/world_environment.cpp
msgid ""
"Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."
-msgstr ""
+msgstr "ÙŠÙØ³Ù…Ø­ Ùقط ببيئة عالمية واحدة لكل مشهد (أو مجموعة من المشاهد المتواÙقة)."
#: scene/3d/world_environment.cpp
msgid ""
"This WorldEnvironment is ignored. Either add a Camera (for 3D scenes) or set "
"this environment's Background Mode to Canvas (for 2D scenes)."
msgstr ""
+"يتم تجاهل هذه البيئة العالمية. إما أن تضي٠كاميرا (للمشاهد ثلاثية Ø§Ù„Ø¨ÙØ¹Ø¯) أو "
+"اضبط وضع الخلÙية لهذه البيئة على لوحة (Canvas) (للمشاهد ثنائية Ø§Ù„Ø¨ÙØ¹Ø¯)."
#: scene/animation/animation_blend_tree.cpp
msgid "On BlendTree node '%s', animation not found: '%s'"
msgstr ""
+"ÙÙŠ عقدة خليط-الشجرة (BlendTree) '%s'ØŒ لم يتم العثور على الرسوم المتحركة:'%s '"
#: scene/animation/animation_blend_tree.cpp
msgid "Animation not found: '%s'"
@@ -12679,12 +12712,18 @@ msgid ""
"children placement behavior.\n"
"If you don't intend to add a script, use a plain Control node instead."
msgstr ""
+"لا تخدم الحاوية ÙÙŠ حد ذاتها أي غرض ما لم يقم النص البرمجي بتكوين سلوك وضع "
+"الأتباع الخاص به .\n"
+"إذا كنت لا تنوي Ø¥Ø¶Ø§ÙØ© نص برمجي ØŒ ÙØ§Ø³ØªØ®Ø¯Ù… عقدة تحكم عادية بدلاً من ذلك."
#: scene/gui/control.cpp
msgid ""
"The Hint Tooltip won't be displayed as the control's Mouse Filter is set to "
"\"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"."
msgstr ""
+"لن يتم عرض أداة التلميح أثناء تعيين عامل تصÙية Ø§Ù„ÙØ£Ø±Ù‡ الخاص بعنصر التحكم, تم "
+"وضعه على \"تجاهل\". لحل هذه المشكلة ØŒ اضبط تصÙية Ø§Ù„ÙØ£Ø±Ù‡ على \"إيقاÙ\" أو "
+"\"تمرير\"."
#: scene/gui/dialogs.cpp
msgid "Alert!"
@@ -12700,10 +12739,13 @@ msgid ""
"functions. Making them visible for editing is fine, but they will hide upon "
"running."
msgstr ""
+"ستختÙÙŠ Ø§Ù„Ù†ÙˆØ§ÙØ° المنبثقة Ø§ÙØªØ±Ø§Ø¶ÙŠÙ‹Ø§ ما لم تقم باستدعاء popup() أو أي من وظائ٠"
+"popup(). من الجيد جعلها مرئية للتحرير ØŒ لكنها ستختÙÙŠ عند التشغيل."
#: scene/gui/range.cpp
msgid "If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."
msgstr ""
+"إذا تم ØªÙØ¹ÙŠÙ„ الـ\"Exp Edit\" يجب على ان يكون \"Min Value\" اعلى من ØµÙØ±."
#: scene/gui/scroll_container.cpp
msgid ""
@@ -12711,6 +12753,9 @@ msgid ""
"Use a container as child (VBox, HBox, etc.), or a Control and set the custom "
"minimum size manually."
msgstr ""
+"تم تصميم ScrollContainer للعمل مع عنصر تحكم تابع واحد.\n"
+"استخدم حاوية كتابع (VBox ، HBox ، إلخ) ، أو عنصر تحكم واضبط الحد الأدنى "
+"المخصص للحجم يدويًا."
#: scene/gui/tree.cpp
msgid "(Other)"
@@ -12721,6 +12766,8 @@ msgid ""
"Default Environment as specified in Project Settings (Rendering -> "
"Environment -> Default Environment) could not be loaded."
msgstr ""
+"تعذر تحميل البيئة Ø§Ù„Ø§ÙØªØ±Ø§Ø¶ÙŠØ© كما هو محدد ÙÙŠ إعدادات المشروع (التقديم -> "
+"البيئة -> البيئة Ø§Ù„Ø§ÙØªØ±Ø§Ø¶ÙŠØ©)."
#: scene/main/viewport.cpp
msgid ""
@@ -12729,6 +12776,9 @@ msgid ""
"obtain a size. Otherwise, make it a RenderTarget and assign its internal "
"texture to some node for display."
msgstr ""
+"لم يتم تعيين Ù…Ù†ÙØ° العرض هذا كهد٠عرض. إذا كنت تنوي عرض محتوياته مباشرة على "
+"الشاشة ، اجعله تابعًا لعنصر تحكم حتى يتمكن من الحصول على الحجم. خلا٠ذلك ، "
+"اجعلها RenderTarget وقم بتعيين نسيجها الداخلي لبعض العقد لعرضها."
#: scene/main/viewport.cpp
msgid "Viewport size must be greater than 0 to render anything."
diff --git a/editor/translations/bg.po b/editor/translations/bg.po
index b0378d612c..6582fc6fec 100644
--- a/editor/translations/bg.po
+++ b/editor/translations/bg.po
@@ -1118,6 +1118,14 @@ msgid "Gold Sponsors"
msgstr ""
#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr ""
diff --git a/editor/translations/bn.po b/editor/translations/bn.po
index 5fdcfb385b..e92b95ae74 100644
--- a/editor/translations/bn.po
+++ b/editor/translations/bn.po
@@ -1215,6 +1215,16 @@ msgid "Gold Sponsors"
msgstr "গোলà§à¦¡ সà§à¦ªà¦¨à¦¸à¦°"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "সিলভার ডোনার"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "বà§à¦°à§‹à¦žà§à¦œ ডোনার"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "মিনি সà§à¦ªà¦¨à¦¸à¦°"
diff --git a/editor/translations/ca.po b/editor/translations/ca.po
index 359aea8184..5f1f1c4cc5 100644
--- a/editor/translations/ca.po
+++ b/editor/translations/ca.po
@@ -1148,6 +1148,16 @@ msgid "Gold Sponsors"
msgstr "Patrocinadors Gold"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Donants Silver"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Donants Bronze"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Mini Patrocinadors"
diff --git a/editor/translations/cs.po b/editor/translations/cs.po
index 0d2ae15065..3a77f37c2a 100644
--- a/editor/translations/cs.po
+++ b/editor/translations/cs.po
@@ -25,8 +25,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-08-11 14:04+0000\n"
-"Last-Translator: Daniel Kříž <Daniel.kriz@protonmail.com>\n"
+"PO-Revision-Date: 2020-08-16 03:50+0000\n"
+"Last-Translator: Zbyněk <zbynek.fiala@gmail.com>\n"
"Language-Team: Czech <https://hosted.weblate.org/projects/godot-engine/godot/"
"cs/>\n"
"Language: cs\n"
@@ -1154,6 +1154,16 @@ msgid "Gold Sponsors"
msgstr "Zlatí sponzoři"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Stříbrní dárci"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Bronzoví dárci"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Malí sponzoři"
@@ -1622,7 +1632,7 @@ msgstr "Editor skriptů"
#: editor/editor_feature_profile.cpp
msgid "Asset Library"
-msgstr "Otevřít knihovnu assetů"
+msgstr "Knihovna zdrojů (AssetLib)"
#: editor/editor_feature_profile.cpp
msgid "Scene Tree Editing"
diff --git a/editor/translations/da.po b/editor/translations/da.po
index da54615917..d472b338d8 100644
--- a/editor/translations/da.po
+++ b/editor/translations/da.po
@@ -1189,6 +1189,16 @@ msgid "Gold Sponsors"
msgstr "Guld Sponsorer"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Sølv Donorer"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Bronze Donorer"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Mini Sponsorer"
diff --git a/editor/translations/de.po b/editor/translations/de.po
index 081dfb8e4f..9b89e7e1d6 100644
--- a/editor/translations/de.po
+++ b/editor/translations/de.po
@@ -55,12 +55,15 @@
# Günther Bohn <ciscouser@gmx.de>, 2020.
# Tom Wor <mail@tomwor.com>, 2020.
# Bjarne Hiller <bjarne.hiller@gmail.com>, 2020.
+# Dirk Federmann <weblategodot@dirkfedermann.de>, 2020.
+# Helmut Hirtes <helmut.h@gmx.de>, 2020.
+# Michal695 <michalek.jedrzejak@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-08-05 16:58+0000\n"
-"Last-Translator: Bjarne Hiller <bjarne.hiller@gmail.com>\n"
+"PO-Revision-Date: 2020-08-28 13:09+0000\n"
+"Last-Translator: Michal695 <michalek.jedrzejak@gmail.com>\n"
"Language-Team: German <https://hosted.weblate.org/projects/godot-engine/"
"godot/de/>\n"
"Language: de\n"
@@ -68,7 +71,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.2-dev\n"
+"X-Generator: Weblate 4.2.1-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -77,13 +80,13 @@ msgstr "Ungültiger Argument-Typ in convert(), TYPE_*-Konstanten benötigt."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
-msgstr "Zeichenkette der Länge 1 erwartet (exakt ein Symbol)."
+msgstr "Zeichenkette der Länge 1 erwartet (exakt ein Zeichen)."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Not enough bytes for decoding bytes, or invalid format."
-msgstr "Nicht genügend Bytes zum Dekodieren oder ungültiges Format."
+msgstr "Nicht genügend Bytes zur Dekodierung oder ungültiges Format."
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
@@ -1194,6 +1197,16 @@ msgid "Gold Sponsors"
msgstr "Gold-Sponsoren"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Silber-Unterstützer"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Bronze-Unterstützer"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Mini-Sponsoren"
@@ -1660,11 +1673,11 @@ msgstr "3D-Editor"
#: editor/editor_feature_profile.cpp
msgid "Script Editor"
-msgstr "Skripteditor"
+msgstr "Skript Editor"
#: editor/editor_feature_profile.cpp
msgid "Asset Library"
-msgstr "Nutzerinhaltesammlung"
+msgstr "Bestandsbibliothek"
#: editor/editor_feature_profile.cpp
msgid "Scene Tree Editing"
@@ -3011,7 +3024,7 @@ msgstr "Projekt abspielen."
#: editor/editor_node.cpp
msgid "Play"
-msgstr "Starten"
+msgstr "Abspielen"
#: editor/editor_node.cpp
msgid "Pause the scene execution for debugging."
@@ -3031,7 +3044,7 @@ msgstr "Spiele die bearbeitete Szene."
#: editor/editor_node.cpp
msgid "Play Scene"
-msgstr "Szene starten"
+msgstr "Szene abspielen"
#: editor/editor_node.cpp
msgid "Play custom scene"
@@ -3039,7 +3052,7 @@ msgstr "Spiele angepasste Szene"
#: editor/editor_node.cpp
msgid "Play Custom Scene"
-msgstr "Spiele angepasste Szene"
+msgstr "Angepasste Szene abspielen"
#: editor/editor_node.cpp
msgid "Changing the video driver requires restarting the editor."
@@ -3256,7 +3269,7 @@ msgstr "Gesamt"
#: editor/editor_profiler.cpp
msgid "Self"
-msgstr "Eigenanteil"
+msgstr "Selbst"
#: editor/editor_profiler.cpp
msgid "Frame #:"
@@ -5695,7 +5708,7 @@ msgstr "Pose kopieren"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear Pose"
-msgstr "Pose zurücksetzen"
+msgstr "Pose/Stellung löschen"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Multiply grid step by 2"
@@ -6833,7 +6846,7 @@ msgstr "Schiebe hoch"
#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Move Down"
-msgstr "Schiebe herunter"
+msgstr "Schiebe runter"
#: editor/plugins/script_editor_plugin.cpp
msgid "Next script"
@@ -6878,7 +6891,7 @@ msgstr "Vorwärts im Verlauf"
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp
msgid "Theme"
-msgstr "Theme"
+msgstr "Designvorlagen (Thema)"
#: editor/plugins/script_editor_plugin.cpp
msgid "Import Theme..."
@@ -7110,7 +7123,7 @@ msgstr "Symbol vervollständigen"
#: editor/plugins/script_text_editor.cpp
msgid "Evaluate Selection"
-msgstr "Auswahl auswerten"
+msgstr "Springe zum vorigen Haltepunkt"
#: editor/plugins/script_text_editor.cpp
msgid "Trim Trailing Whitespace"
@@ -9398,9 +9411,9 @@ msgid ""
"Returns falloff based on the dot product of surface normal and view "
"direction of camera (pass associated inputs to it)."
msgstr ""
-"Gibt den Fresnelabfall abgeleitet aus dem Skalarprodukt aus "
-"Oberflächennormalenvektor und Kamerablickrichtung zurück (zugeordnete "
-"Eingänge müssen übergeben werden)."
+"Gibt den Abfall basierend auf dem Punktprodukt der Oberflächennormalen und "
+"der Blickrichtung der Kamera zurück (übergeben Sie die zugehörigen Eingaben "
+"an diese)."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -10323,7 +10336,7 @@ msgstr "Umleitungen nach Lokalisierung:"
#: editor/project_settings_editor.cpp
msgid "Locale"
-msgstr "Lokalisierung"
+msgstr "Gebietsschema"
#: editor/project_settings_editor.cpp
msgid "Locales Filter"
@@ -10756,7 +10769,7 @@ msgstr "Unter-Ressourcen"
#: editor/scene_tree_dock.cpp
msgid "Clear Inheritance"
-msgstr "Leere Vererbung"
+msgstr "Löse Vererbung"
#: editor/scene_tree_dock.cpp
msgid "Editable Children"
@@ -10845,7 +10858,7 @@ msgstr "Lokal"
#: editor/scene_tree_dock.cpp
msgid "Clear Inheritance? (No Undo!)"
-msgstr "Vererbung wirklich leeren? (Lässt sich nicht rückgängig machen!)"
+msgstr "Vererbung wirklich lösen? (Lässt sich nicht rückgängig machen!)"
#: editor/scene_tree_editor.cpp
msgid "Toggle Visible"
@@ -11926,7 +11939,7 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Delete Selected"
-msgstr "Ausgewähltes löschen"
+msgstr "Auswahl löschen"
#: modules/visual_script/visual_script_editor.cpp
msgid "Find Node Type"
@@ -11942,7 +11955,7 @@ msgstr "Nodes trennen"
#: modules/visual_script/visual_script_editor.cpp
msgid "Make Function"
-msgstr "Funktion bauen"
+msgstr "Funktion erstellen"
#: modules/visual_script/visual_script_editor.cpp
msgid "Refresh Graph"
diff --git a/editor/translations/editor.pot b/editor/translations/editor.pot
index 87dca17afd..93e62289e0 100644
--- a/editor/translations/editor.pot
+++ b/editor/translations/editor.pot
@@ -1101,6 +1101,14 @@ msgid "Gold Sponsors"
msgstr ""
#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr ""
diff --git a/editor/translations/el.po b/editor/translations/el.po
index 7c2a202767..c0c08edc2f 100644
--- a/editor/translations/el.po
+++ b/editor/translations/el.po
@@ -1147,6 +1147,16 @@ msgid "Gold Sponsors"
msgstr "ΧÏυσοί ΧοÏυγοί"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "ΑÏγυÏοί ΔωÏητές"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Χάλκινοι ΔωÏητές"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "ΜικÏοί ΧοÏηγοί"
diff --git a/editor/translations/eo.po b/editor/translations/eo.po
index e740ea7d7a..3b58b56f85 100644
--- a/editor/translations/eo.po
+++ b/editor/translations/eo.po
@@ -1140,6 +1140,14 @@ msgid "Gold Sponsors"
msgstr ""
#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr ""
diff --git a/editor/translations/es.po b/editor/translations/es.po
index 172ce58604..a685eeb7ff 100644
--- a/editor/translations/es.po
+++ b/editor/translations/es.po
@@ -1193,6 +1193,16 @@ msgid "Gold Sponsors"
msgstr "Patrocinadores Oro"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Donantes Plata"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Donantes Bronce"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Mini Patrocinadores"
diff --git a/editor/translations/es_AR.po b/editor/translations/es_AR.po
index f2c72ce1be..f80c3ba2c0 100644
--- a/editor/translations/es_AR.po
+++ b/editor/translations/es_AR.po
@@ -1154,6 +1154,16 @@ msgid "Gold Sponsors"
msgstr "Sponsor Oro"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Donantes Plata"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Donantes Bronce"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Mini Sponsors"
diff --git a/editor/translations/et.po b/editor/translations/et.po
index 504de558d5..b2b51b8676 100644
--- a/editor/translations/et.po
+++ b/editor/translations/et.po
@@ -9,7 +9,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
-"PO-Revision-Date: 2020-08-11 14:04+0000\n"
+"PO-Revision-Date: 2020-09-01 10:38+0000\n"
"Last-Translator: StReef <streef.gtx@gmail.com>\n"
"Language-Team: Estonian <https://hosted.weblate.org/projects/godot-engine/"
"godot/et/>\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8-bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.2-dev\n"
+"X-Generator: Weblate 4.2.1-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -799,7 +799,7 @@ msgstr ""
#: editor/connections_dialog.cpp
msgid "Advanced"
-msgstr ""
+msgstr "Täpsem"
#: editor/connections_dialog.cpp
msgid "Deferred"
@@ -912,23 +912,23 @@ msgstr ""
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp
msgid "Favorites:"
-msgstr ""
+msgstr "Lemmikud:"
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
msgid "Recent:"
-msgstr ""
+msgstr "Hiljutised:"
#: editor/create_dialog.cpp editor/plugins/script_editor_plugin.cpp
#: editor/property_selector.cpp editor/quick_open.cpp
#: modules/visual_script/visual_script_property_selector.cpp
msgid "Search:"
-msgstr ""
+msgstr "Otsi:"
#: editor/create_dialog.cpp editor/plugins/script_editor_plugin.cpp
#: editor/property_selector.cpp editor/quick_open.cpp
#: modules/visual_script/visual_script_property_selector.cpp
msgid "Matches:"
-msgstr ""
+msgstr "Vasted:"
#: editor/create_dialog.cpp editor/editor_plugin_settings.cpp
#: editor/plugin_config_dialog.cpp
@@ -936,7 +936,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp editor/property_selector.cpp
#: modules/visual_script/visual_script_property_selector.cpp
msgid "Description:"
-msgstr ""
+msgstr "Kirjeldus:"
#: editor/dependency_editor.cpp
msgid "Search Replacement For:"
@@ -1059,7 +1059,7 @@ msgstr ""
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp
#: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp
msgid "Delete"
-msgstr ""
+msgstr "Kustuta"
#: editor/dependency_editor.cpp
msgid "Owns"
@@ -1079,7 +1079,7 @@ msgstr ""
#: editor/editor_about.cpp
msgid "Thanks from the Godot community!"
-msgstr "Tänu Godot kogukonnale!"
+msgstr "Suur tänu Godot kogukonnalt!"
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
@@ -1114,6 +1114,16 @@ msgid "Gold Sponsors"
msgstr "Kuldsponsorid"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Hõbennetajad"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Pronksannetajad"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Väikesponsorid"
@@ -1148,14 +1158,18 @@ msgid ""
"is an exhaustive list of all such third-party components with their "
"respective copyright statements and license terms."
msgstr ""
+"Godot mängumootor tugineb mitmetele kolmandate osapoolte tasuta ja avatud "
+"lähtekoodiga teekidele, mis kõik on kooskõlas MIT-litsentsi tingimustega. "
+"Järgnev on kõigi selliste kolmandate osapoolte komponentide täielik loetelu "
+"koos vastavate autoriõiguste avalduste ja litsentsitingimustega."
#: editor/editor_about.cpp
msgid "All Components"
-msgstr ""
+msgstr "Kõik komponendid"
#: editor/editor_about.cpp
msgid "Components"
-msgstr ""
+msgstr "Komponendid"
#: editor/editor_about.cpp
msgid "Licenses"
@@ -1204,7 +1218,7 @@ msgstr ""
#: editor/editor_audio_buses.cpp
msgid "Speakers"
-msgstr ""
+msgstr "Heliväljundi"
#: editor/editor_audio_buses.cpp
msgid "Add Effect"
@@ -1269,7 +1283,7 @@ msgstr ""
#: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "Duplicate"
-msgstr ""
+msgstr "Duplikeeri"
#: editor/editor_audio_buses.cpp
msgid "Reset Volume"
@@ -2287,15 +2301,15 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Quick Open..."
-msgstr ""
+msgstr "Ava kiiresti..."
#: editor/editor_node.cpp
msgid "Quick Open Scene..."
-msgstr ""
+msgstr "Ava kiiresti stseen..."
#: editor/editor_node.cpp
msgid "Quick Open Script..."
-msgstr ""
+msgstr "Ava kiiresti skript..."
#: editor/editor_node.cpp
msgid "Save & Close"
@@ -2423,22 +2437,28 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
-msgstr ""
+msgstr "Lisa-skripti ei olnud võimalik laadida teelt: '%s'."
#: editor/editor_node.cpp
msgid ""
"Unable to load addon script from path: '%s' There seems to be an error in "
"the code, please check the syntax."
msgstr ""
+"Lisa-skripti ei olnud võimalik laadida teelt: '%s'. Tundub, et koodis on "
+"viga, palun kontrolli süntaksi."
#: editor/editor_node.cpp
msgid ""
"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
msgstr ""
+"Lisa-skripti ei olnud võimalik laadida teelt: '%s'. Baastüüp ei ole "
+"EditorPlugin."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
msgstr ""
+"Lisa-skripti ei olnud võimalik laadida teelt: '%s'. Skript ei ole tööriista "
+"režiimis."
#: editor/editor_node.cpp
msgid ""
@@ -2609,7 +2629,7 @@ msgstr "Salvesta kõik stseenid"
#: editor/editor_node.cpp
msgid "Convert To..."
-msgstr ""
+msgstr "Teisenda..."
#: editor/editor_node.cpp
msgid "MeshLibrary..."
@@ -2827,7 +2847,7 @@ msgstr "Teavita veast"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
-msgstr "Saada dokumentatsioonide tagasisede"
+msgstr "Saada dokumentatsioonide tagasiside"
#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
msgid "Community"
@@ -2971,7 +2991,7 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Load Errors"
-msgstr ""
+msgstr "Laadimisvead"
#: editor/editor_node.cpp editor/plugins/tile_map_editor_plugin.cpp
msgid "Select"
@@ -3027,36 +3047,36 @@ msgstr ""
#: editor/editor_plugin_settings.cpp
msgid "Installed Plugins:"
-msgstr ""
+msgstr "Paigaldatud pistikprogrammid:"
#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
msgid "Update"
-msgstr ""
+msgstr "Uuenda"
#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Version:"
-msgstr ""
+msgstr "Versioon:"
#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp
msgid "Author:"
-msgstr ""
+msgstr "Autor:"
#: editor/editor_plugin_settings.cpp
msgid "Status:"
-msgstr ""
+msgstr "Olek:"
#: editor/editor_plugin_settings.cpp
msgid "Edit:"
-msgstr ""
+msgstr "Muuda:"
#: editor/editor_profiler.cpp
msgid "Measure:"
-msgstr ""
+msgstr "Mõõda:"
#: editor/editor_profiler.cpp
msgid "Frame Time (sec)"
-msgstr ""
+msgstr "Kaadri aeg (sek)"
#: editor/editor_profiler.cpp
msgid "Average Time (sec)"
@@ -3064,7 +3084,7 @@ msgstr ""
#: editor/editor_profiler.cpp
msgid "Frame %"
-msgstr ""
+msgstr "Kaadri %"
#: editor/editor_profiler.cpp
msgid "Physics Frame %"
@@ -3080,15 +3100,15 @@ msgstr ""
#: editor/editor_profiler.cpp
msgid "Frame #:"
-msgstr ""
+msgstr "Kaader nr:"
#: editor/editor_profiler.cpp
msgid "Time"
-msgstr ""
+msgstr "Aeg"
#: editor/editor_profiler.cpp
msgid "Calls"
-msgstr ""
+msgstr "Kutsungid"
#: editor/editor_properties.cpp
msgid "Edit Text:"
@@ -3140,15 +3160,15 @@ msgstr ""
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "Pick a Viewport"
-msgstr ""
+msgstr "Vali vaateaken"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "New Script"
-msgstr ""
+msgstr "Uus skript"
#: editor/editor_properties.cpp editor/scene_tree_dock.cpp
msgid "Extend Script"
-msgstr ""
+msgstr "Laienda skripti"
#: editor/editor_properties.cpp editor/property_editor.cpp
msgid "New %s"
@@ -3199,7 +3219,7 @@ msgstr ""
#: editor/editor_properties_array_dict.cpp
msgid "New Value:"
-msgstr ""
+msgstr "Uus väärtus:"
#: editor/editor_properties_array_dict.cpp
msgid "Add Key/Value Pair"
@@ -3428,7 +3448,7 @@ msgstr ""
#: editor/export_template_manager.cpp
msgid "Current Version:"
-msgstr ""
+msgstr "Praegune versioon:"
#: editor/export_template_manager.cpp
msgid "Installed Versions:"
@@ -3540,7 +3560,7 @@ msgstr ""
#: editor/filesystem_dock.cpp
msgid "Add to Favorites"
-msgstr ""
+msgstr "Lisa lemmikutesse"
#: editor/filesystem_dock.cpp
msgid "Remove from Favorites"
@@ -3548,45 +3568,45 @@ msgstr ""
#: editor/filesystem_dock.cpp
msgid "Edit Dependencies..."
-msgstr ""
+msgstr "Redigeeri sõltuvusi..."
#: editor/filesystem_dock.cpp
msgid "View Owners..."
-msgstr ""
+msgstr "Kuva omanikud..."
#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Rename..."
-msgstr ""
+msgstr "Muuda nime..."
#: editor/filesystem_dock.cpp
msgid "Duplicate..."
-msgstr ""
+msgstr "Duplikeeri..."
#: editor/filesystem_dock.cpp
msgid "Move To..."
-msgstr ""
+msgstr "Teisalda..."
#: editor/filesystem_dock.cpp
msgid "New Scene..."
-msgstr ""
+msgstr "Uus stseen..."
#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
msgid "New Script..."
-msgstr ""
+msgstr "Uus skript..."
#: editor/filesystem_dock.cpp
msgid "New Resource..."
-msgstr ""
+msgstr "Uus ressurss..."
#: editor/filesystem_dock.cpp editor/plugins/visual_shader_editor_plugin.cpp
#: editor/script_editor_debugger.cpp
msgid "Expand All"
-msgstr ""
+msgstr "Laienda kõik"
#: editor/filesystem_dock.cpp editor/plugins/visual_shader_editor_plugin.cpp
#: editor/script_editor_debugger.cpp
msgid "Collapse All"
-msgstr ""
+msgstr "Ahenda kõik"
#: editor/filesystem_dock.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
@@ -3597,11 +3617,11 @@ msgstr "Nimeta ümber"
#: editor/filesystem_dock.cpp
msgid "Previous Folder/File"
-msgstr ""
+msgstr "Eelmine kaust/fail"
#: editor/filesystem_dock.cpp
msgid "Next Folder/File"
-msgstr ""
+msgstr "Järgmine kaust/fail"
#: editor/filesystem_dock.cpp
msgid "Re-Scan Filesystem"
@@ -3609,7 +3629,7 @@ msgstr ""
#: editor/filesystem_dock.cpp
msgid "Toggle Split Mode"
-msgstr ""
+msgstr "Lülita jagamisrežiim sisse/välja"
#: editor/filesystem_dock.cpp
msgid "Search files"
@@ -3639,7 +3659,7 @@ msgstr "Loo stseen"
#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp
msgid "Create Script"
-msgstr ""
+msgstr "Loo skript"
#: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp
msgid "Find in Files"
@@ -3954,7 +3974,7 @@ msgstr ""
#: editor/plugin_config_dialog.cpp
msgid "Edit a Plugin"
-msgstr ""
+msgstr "Pistikprogrammi muutmine"
#: editor/plugin_config_dialog.cpp
msgid "Create a Plugin"
@@ -3962,7 +3982,7 @@ msgstr ""
#: editor/plugin_config_dialog.cpp
msgid "Plugin Name:"
-msgstr ""
+msgstr "Pistikprogrammi nimi:"
#: editor/plugin_config_dialog.cpp
msgid "Subfolder:"
@@ -3970,11 +3990,11 @@ msgstr ""
#: editor/plugin_config_dialog.cpp editor/script_create_dialog.cpp
msgid "Language:"
-msgstr ""
+msgstr "Keel:"
#: editor/plugin_config_dialog.cpp
msgid "Script Name:"
-msgstr ""
+msgstr "Skripti nimi:"
#: editor/plugin_config_dialog.cpp
msgid "Activate now?"
@@ -4214,7 +4234,7 @@ msgstr ""
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/scene_tree_dock.cpp
msgid "Delete Node(s)"
-msgstr ""
+msgstr "Kustuta sõlm(ed)"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Toggle Filter On/Off"
@@ -4379,7 +4399,7 @@ msgstr "Animatsiooni tööriistad"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation"
-msgstr ""
+msgstr "Animatsioon"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Edit Transitions..."
@@ -4443,7 +4463,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Include Gizmos (3D)"
-msgstr ""
+msgstr "Kaasa vidinad (3D)"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Pin AnimationPlayer"
@@ -4715,7 +4735,7 @@ msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "View Files"
-msgstr ""
+msgstr "Kuva failid"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Connection error, please try again."
@@ -4875,7 +4895,7 @@ msgstr ""
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Plugins..."
-msgstr ""
+msgstr "Pistikprogrammid..."
#: editor/plugins/asset_library_editor_plugin.cpp editor/project_manager.cpp
msgid "Sort:"
@@ -4934,7 +4954,7 @@ msgstr ""
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp editor/rename_dialog.cpp
msgid "Preview"
-msgstr ""
+msgstr "Eelvaade"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Configure Snap"
@@ -5349,7 +5369,7 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View"
-msgstr ""
+msgstr "Kuva"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Always Show Grid"
@@ -5373,7 +5393,7 @@ msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Viewport"
-msgstr ""
+msgstr "Kuva vaateaken"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Group And Lock Icons"
@@ -6392,7 +6412,7 @@ msgstr ""
#: editor/scene_tree_editor.cpp editor/script_editor_debugger.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Type:"
-msgstr ""
+msgstr "Tüüp:"
#: editor/plugins/resource_preloader_editor_plugin.cpp
#: editor/scene_tree_dock.cpp editor/scene_tree_editor.cpp
@@ -6530,21 +6550,21 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Move Up"
-msgstr ""
+msgstr "Liiguta üles"
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Move Down"
-msgstr ""
+msgstr "Liiguta allapoole"
#: editor/plugins/script_editor_plugin.cpp
msgid "Next script"
-msgstr ""
+msgstr "Järgmine skript"
#: editor/plugins/script_editor_plugin.cpp
msgid "Previous script"
-msgstr ""
+msgstr "Eelmine skript"
#: editor/plugins/script_editor_plugin.cpp
msgid "File"
@@ -6617,12 +6637,12 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp
msgid "Break"
-msgstr ""
+msgstr "Paus"
#: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp
#: editor/script_editor_debugger.cpp
msgid "Continue"
-msgstr ""
+msgstr "Jätka"
#: editor/plugins/script_editor_plugin.cpp
msgid "Keep Debugger Open"
@@ -7095,7 +7115,7 @@ msgstr "Kuva keskkond"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Gizmos"
-msgstr ""
+msgstr "Kuva vidinad"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Information"
@@ -7262,44 +7282,44 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "1 Viewport"
-msgstr ""
+msgstr "1 vaateaken"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "2 Viewports"
-msgstr ""
+msgstr "2 vaateakent"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "2 Viewports (Alt)"
-msgstr ""
+msgstr "2 vaateakent (alt)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "3 Viewports"
-msgstr ""
+msgstr "3 vaateakent"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "3 Viewports (Alt)"
-msgstr ""
+msgstr "3 vaateakent (alt)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "4 Viewports"
-msgstr ""
+msgstr "4 vaateakent"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Gizmos"
-msgstr ""
+msgstr "Vidinad"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Origin"
-msgstr ""
+msgstr "Kuva lähtekoht"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Grid"
-msgstr ""
+msgstr "Kuva ruudustik"
#: editor/plugins/spatial_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Settings..."
-msgstr ""
+msgstr "Sätted..."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Settings"
@@ -7319,7 +7339,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Viewport Settings"
-msgstr ""
+msgstr "Vaateakna sätted"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Perspective FOV (deg.):"
@@ -7475,7 +7495,7 @@ msgstr ""
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Unable to load images"
-msgstr ""
+msgstr "Pilte ei saa laadida"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "ERROR: Couldn't load frame resource!"
@@ -7748,7 +7768,7 @@ msgstr ""
#: editor/plugins/theme_editor_plugin.cpp
msgid "Data Type:"
-msgstr ""
+msgstr "Andmetüüp:"
#: editor/plugins/theme_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp
@@ -7876,7 +7896,7 @@ msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Merge from Scene"
-msgstr ""
+msgstr "Liida stseenist"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "New Single Tile"
@@ -8247,7 +8267,7 @@ msgstr ""
#: editor/plugins/version_control_editor_plugin.cpp
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Status"
-msgstr ""
+msgstr "Olek"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "View file diffs before committing them to the latest version"
@@ -9119,7 +9139,7 @@ msgstr ""
#: editor/project_export.cpp editor/project_settings_editor.cpp
msgid "Add..."
-msgstr ""
+msgstr "Lisa..."
#: editor/project_export.cpp
msgid ""
@@ -9193,7 +9213,7 @@ msgstr ""
#: editor/project_export.cpp
msgid "Script"
-msgstr ""
+msgstr "Skript"
#: editor/project_export.cpp
msgid "Script Export Mode:"
@@ -9807,15 +9827,15 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Localization"
-msgstr ""
+msgstr "Tõlked"
#: editor/project_settings_editor.cpp
msgid "Translations"
-msgstr ""
+msgstr "Tõlked"
#: editor/project_settings_editor.cpp
msgid "Translations:"
-msgstr ""
+msgstr "Tõlked:"
#: editor/project_settings_editor.cpp
msgid "Remaps"
@@ -9859,7 +9879,7 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Plugins"
-msgstr ""
+msgstr "Pistikprogrammid"
#: editor/property_editor.cpp
msgid "Preset..."
@@ -9935,7 +9955,7 @@ msgstr ""
#: editor/rename_dialog.cpp
msgid "Advanced Options"
-msgstr ""
+msgstr "Täpsemad sätted"
#: editor/rename_dialog.cpp
msgid "Substitute"
@@ -10218,7 +10238,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Attach Script"
-msgstr ""
+msgstr "Manusta skript"
#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
@@ -10244,7 +10264,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Sub-Resources"
-msgstr ""
+msgstr "Alamressursid"
#: editor/scene_tree_dock.cpp
msgid "Clear Inheritance"
@@ -10260,7 +10280,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Open Documentation"
-msgstr ""
+msgstr "Ava dokumentatsioon"
#: editor/scene_tree_dock.cpp
msgid ""
@@ -10275,11 +10295,11 @@ msgstr "Lisa alamsõlm"
#: editor/scene_tree_dock.cpp
msgid "Expand/Collapse All"
-msgstr ""
+msgstr "Laienda/ahenda kõik"
#: editor/scene_tree_dock.cpp
msgid "Change Type"
-msgstr ""
+msgstr "Muuda tüüpi"
#: editor/scene_tree_dock.cpp
msgid "Reparent to New Node"
@@ -10287,7 +10307,7 @@ msgstr ""
#: editor/scene_tree_dock.cpp
msgid "Make Scene Root"
-msgstr ""
+msgstr "Tee stseeni juurikaks"
#: editor/scene_tree_dock.cpp
msgid "Merge From Scene"
@@ -10295,11 +10315,11 @@ msgstr ""
#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
msgid "Save Branch as Scene"
-msgstr ""
+msgstr "Salvesta filiaal stseenina"
#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp
msgid "Copy Node Path"
-msgstr ""
+msgstr "Kopeeri sõlme tee"
#: editor/scene_tree_dock.cpp
msgid "Delete (No Confirm)"
@@ -10477,7 +10497,7 @@ msgstr ""
#: editor/script_create_dialog.cpp
msgid "Open Script"
-msgstr ""
+msgstr "Ava skript"
#: editor/script_create_dialog.cpp
msgid "File exists, it will be reused."
@@ -10583,7 +10603,7 @@ msgstr ""
#: editor/script_editor_debugger.cpp
msgid "Errors"
-msgstr ""
+msgstr "Vead"
#: editor/script_editor_debugger.cpp
msgid "Child process connected."
@@ -10591,11 +10611,11 @@ msgstr ""
#: editor/script_editor_debugger.cpp
msgid "Copy Error"
-msgstr ""
+msgstr "Kopeeri viga"
#: editor/script_editor_debugger.cpp
msgid "Video RAM"
-msgstr ""
+msgstr "Videomälu"
#: editor/script_editor_debugger.cpp
msgid "Skip Breakpoints"
@@ -10611,7 +10631,7 @@ msgstr ""
#: editor/script_editor_debugger.cpp
msgid "Stack Frames"
-msgstr ""
+msgstr "Virnakaadrid"
#: editor/script_editor_debugger.cpp
msgid "Profiler"
@@ -10623,15 +10643,15 @@ msgstr ""
#: editor/script_editor_debugger.cpp
msgid "Monitor"
-msgstr ""
+msgstr "Jälgija"
#: editor/script_editor_debugger.cpp
msgid "Value"
-msgstr ""
+msgstr "Väärtus"
#: editor/script_editor_debugger.cpp
msgid "Monitors"
-msgstr ""
+msgstr "Jälgijad"
#: editor/script_editor_debugger.cpp
msgid "Pick one or more items from the list to display the graph."
@@ -10639,7 +10659,7 @@ msgstr ""
#: editor/script_editor_debugger.cpp
msgid "List of Video Memory Usage by Resource:"
-msgstr ""
+msgstr "Videomälu kasutamise loetelu ressursside kaupa:"
#: editor/script_editor_debugger.cpp
msgid "Total:"
@@ -10651,7 +10671,7 @@ msgstr ""
#: editor/script_editor_debugger.cpp
msgid "Resource Path"
-msgstr ""
+msgstr "Ressursi tee"
#: editor/script_editor_debugger.cpp
msgid "Type"
@@ -10659,15 +10679,15 @@ msgstr ""
#: editor/script_editor_debugger.cpp
msgid "Format"
-msgstr ""
+msgstr "Formaat"
#: editor/script_editor_debugger.cpp
msgid "Usage"
-msgstr ""
+msgstr "Kasutus"
#: editor/script_editor_debugger.cpp
msgid "Misc"
-msgstr ""
+msgstr "Muud"
#: editor/script_editor_debugger.cpp
msgid "Clicked Control:"
@@ -10686,8 +10706,9 @@ msgid "Set From Tree"
msgstr ""
#: editor/script_editor_debugger.cpp
+#, fuzzy
msgid "Export measures as CSV"
-msgstr ""
+msgstr "Ekspordi mõõtmed/meetmed CSV-vormingus"
#: editor/settings_config_dialog.cpp
msgid "Erase Shortcut"
@@ -10831,11 +10852,11 @@ msgstr ""
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Library"
-msgstr ""
+msgstr "Teek"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Libraries: "
-msgstr ""
+msgstr "Teegid: "
#: modules/gdnative/register_types.cpp
msgid "GDNative"
diff --git a/editor/translations/eu.po b/editor/translations/eu.po
index 906a258f32..f2f5f51348 100644
--- a/editor/translations/eu.po
+++ b/editor/translations/eu.po
@@ -1111,6 +1111,16 @@ msgid "Gold Sponsors"
msgstr "Urrezko babesleak"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Zilarrezko emaileak"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Brontzezko emaileak"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Mini babesleak"
diff --git a/editor/translations/fa.po b/editor/translations/fa.po
index dc7ae9ec69..0b87c12532 100644
--- a/editor/translations/fa.po
+++ b/editor/translations/fa.po
@@ -1141,6 +1141,16 @@ msgid "Gold Sponsors"
msgstr "حامیان طلایی (درجه ۲)"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "اهداکنندگان نقره‌ای"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "اهداکنندگان برنزی"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "اسپانسر‌های کوچک"
diff --git a/editor/translations/fi.po b/editor/translations/fi.po
index 124ae4f2e0..62c2e7a951 100644
--- a/editor/translations/fi.po
+++ b/editor/translations/fi.po
@@ -1138,6 +1138,16 @@ msgid "Gold Sponsors"
msgstr "Kultasponsorit"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Hopealahjoittajat"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Pronssilahjoittajat"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Minisponsorit"
diff --git a/editor/translations/fil.po b/editor/translations/fil.po
index 490d9d92ec..faf4436839 100644
--- a/editor/translations/fil.po
+++ b/editor/translations/fil.po
@@ -5,11 +5,12 @@
# Marco Santos <enum.scima@gmail.com>, 2019.
# Amado Wilkins <epicalert68@gmail.com>, 2019.
# Bakainkorp <Ryan.Bautista86@myhunter.cuny.edu>, 2019.
+# Jethro Parker <lionbearjet@hotmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
-"PO-Revision-Date: 2019-12-21 08:37+0000\n"
-"Last-Translator: Bakainkorp <Ryan.Bautista86@myhunter.cuny.edu>\n"
+"PO-Revision-Date: 2020-08-14 03:56+0000\n"
+"Last-Translator: Jethro Parker <lionbearjet@hotmail.com>\n"
"Language-Team: Filipino <https://hosted.weblate.org/projects/godot-engine/"
"godot/fil/>\n"
"Language: fil\n"
@@ -17,7 +18,7 @@ msgstr ""
"Content-Transfer-Encoding: 8-bit\n"
"Plural-Forms: nplurals=2; plural=n != 1 && n != 2 && n != 3 && (n % 10 == 4 "
"|| n % 10 == 6 || n % 10 == 9);\n"
-"X-Generator: Weblate 3.10\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -28,7 +29,7 @@ msgstr ""
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
-msgstr ""
+msgstr "Nanghihingi ng string na may habang 1 (character)."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
@@ -185,12 +186,12 @@ msgstr ""
#: editor/animation_track_editor.cpp
msgid "Change Animation Length"
-msgstr ""
+msgstr "Ibahin ang haba ng Animation"
#: editor/animation_track_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Change Animation Loop"
-msgstr ""
+msgstr "Ibahin ang ulit ng Animation"
#: editor/animation_track_editor.cpp
msgid "Property Track"
@@ -218,44 +219,44 @@ msgstr ""
#: editor/animation_track_editor.cpp
msgid "Animation length (frames)"
-msgstr ""
+msgstr "Haba ng animation (frames)"
#: editor/animation_track_editor.cpp
msgid "Animation length (seconds)"
-msgstr ""
+msgstr "Haba ng animation (segundo)"
#: editor/animation_track_editor.cpp
msgid "Add Track"
-msgstr ""
+msgstr "Magdagdag ng Track"
#: editor/animation_track_editor.cpp
msgid "Animation Looping"
-msgstr ""
+msgstr "Pagulit ng Animation"
#: editor/animation_track_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Functions:"
-msgstr ""
+msgstr "Functions:"
#: editor/animation_track_editor.cpp
msgid "Audio Clips:"
-msgstr ""
+msgstr "Mga clip ng tunog:"
#: editor/animation_track_editor.cpp
msgid "Anim Clips:"
-msgstr ""
+msgstr "Mga clip ng Anim:"
#: editor/animation_track_editor.cpp
msgid "Change Track Path"
-msgstr ""
+msgstr "Ibahin ang landas ng Track"
#: editor/animation_track_editor.cpp
msgid "Toggle this track on/off."
-msgstr ""
+msgstr "Ilipat sa on/off ang track na ito."
#: editor/animation_track_editor.cpp
msgid "Update Mode (How this property is set)"
-msgstr ""
+msgstr "Baguhin ang Mode (Kung paano na-set ang property)"
#: editor/animation_track_editor.cpp
msgid "Interpolation Mode"
@@ -1114,6 +1115,14 @@ msgid "Gold Sponsors"
msgstr ""
#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr ""
@@ -1893,7 +1902,7 @@ msgstr ""
#: editor/editor_help.cpp
msgid "Description"
-msgstr ""
+msgstr "Paglalarawan"
#: editor/editor_help.cpp
msgid "Online Tutorials"
@@ -2816,11 +2825,11 @@ msgstr ""
#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
msgid "Community"
-msgstr ""
+msgstr "Komunidad"
#: editor/editor_node.cpp
msgid "About"
-msgstr ""
+msgstr "Tungkol"
#: editor/editor_node.cpp
msgid "Play the project."
diff --git a/editor/translations/fr.po b/editor/translations/fr.po
index 9bb04cb2b0..8c1d67af83 100644
--- a/editor/translations/fr.po
+++ b/editor/translations/fr.po
@@ -1217,6 +1217,16 @@ msgid "Gold Sponsors"
msgstr "Sponsors Or"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Donateurs Argent"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Donateurs Bronze"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Mini Sponsors"
diff --git a/editor/translations/ga.po b/editor/translations/ga.po
index a496566c2e..da64cfe007 100644
--- a/editor/translations/ga.po
+++ b/editor/translations/ga.po
@@ -1107,6 +1107,14 @@ msgid "Gold Sponsors"
msgstr ""
#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr ""
diff --git a/editor/translations/he.po b/editor/translations/he.po
index 0f9a19c842..48bb2ad5c0 100644
--- a/editor/translations/he.po
+++ b/editor/translations/he.po
@@ -15,11 +15,12 @@
# Anonymous <noreply@weblate.org>, 2020.
# Daniel Kariv <danielkariv98@gmail.com>, 2020.
# Ziv D <wizdavid@gmail.com>, 2020.
+# yariv benj <yariv4400@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-08-11 14:04+0000\n"
+"PO-Revision-Date: 2020-09-04 06:51+0000\n"
"Last-Translator: Ziv D <wizdavid@gmail.com>\n"
"Language-Team: Hebrew <https://hosted.weblate.org/projects/godot-engine/"
"godot/he/>\n"
@@ -29,16 +30,16 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n == 1) ? 0 : ((n == 2) ? 1 : ((n > 10 && "
"n % 10 == 0) ? 2 : 3));\n"
-"X-Generator: Weblate 4.2-dev\n"
+"X-Generator: Weblate 4.3-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Invalid type argument to convert(), use TYPE_* constants."
-msgstr "משתנה סוג ×œ× ×—×•×§×™ לפונקציית convert()‎, יש להשתמש בקבועי TYPE_*‎."
+msgstr "סוג משתנה ×œ× ×—×•×§×™ לפונקציית convert()‎, יש להשתמש בקבועי TYPE_*‎."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
-msgstr "צפויה מחרוזת ב×ורך 1 (תו)."
+msgstr "היתה צפויה מחרוזת ב×ורך 1 (תו)."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
@@ -52,7 +53,7 @@ msgstr "קלט שגוי %I (×œ× ×”×•×¢×‘×¨) בתוך הביטוי"
#: core/math/expression.cpp
msgid "self can't be used because instance is null (not passed)"
-msgstr "×œ× × ×™×ª×Ÿ להשתמש ב־self כיוון שהמופע ×”×•× ×פס (null - ×œ× ×”×•×¢×‘×¨)"
+msgstr "'self' ×œ× × ×™×ª×Ÿ לשימוש ×›×™ המופע הינו 'null' ( ×œ× ×”×•×¢×‘×¨)"
#: core/math/expression.cpp
msgid "Invalid operands to operator %s, %s and %s."
@@ -64,7 +65,7 @@ msgstr "×©× ×ž×פיין ×”×ינדקס מסוג %s עבור בסיס %s שגו
#: core/math/expression.cpp
msgid "Invalid named index '%s' for base type %s"
-msgstr "×©× ×ינדקס ×œ× ×ª×§×™×Ÿ '%s' לסוג בסיס '%s'"
+msgstr "×©× ×ינדקס ×œ× ×ª×§×™×Ÿ '%s' לסוג בסיס %s"
#: core/math/expression.cpp
msgid "Invalid arguments to construct '%s'"
@@ -76,7 +77,7 @@ msgstr "בקרי××” ל־‚%s’:"
#: core/ustring.cpp
msgid "B"
-msgstr "ב׳"
+msgstr "B"
#: core/ustring.cpp
msgid "KiB"
@@ -124,15 +125,15 @@ msgstr "ערך:"
#: editor/animation_bezier_editor.cpp
msgid "Insert Key Here"
-msgstr "הכנס מפתח ×›×ן"
+msgstr "הכנס ×›×ן מפתח"
#: editor/animation_bezier_editor.cpp
msgid "Duplicate Selected Key(s)"
-msgstr "לשכפל ×ת ×”×§×‘×¦×™× ×”× ×‘×—×¨×™×"
+msgstr "שכפול מפתח(ות) שנבחרו"
#: editor/animation_bezier_editor.cpp
msgid "Delete Selected Key(s)"
-msgstr "למחוק ×ת ×”×§×‘×¦×™× ×”× ×‘×—×¨×™×"
+msgstr "מחיקת מפתח(ות) שנבחרו"
#: editor/animation_bezier_editor.cpp
msgid "Add Bezier Point"
@@ -267,7 +268,7 @@ msgstr "עדכן מצב (×יך המ×פיין ×”×–×” נקבע)"
#: editor/animation_track_editor.cpp
msgid "Interpolation Mode"
-msgstr "מצב ×ינתרפולציה"
+msgstr "מצב ×ינטרפולציה"
#: editor/animation_track_editor.cpp
msgid "Loop Wrap Mode (Interpolate end with beginning on loop)"
@@ -336,7 +337,6 @@ msgid "Delete Key(s)"
msgstr "מחיקת מפתח(ות)"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Change Animation Update Mode"
msgstr "שינוי מצב עדכון הנפשה"
@@ -373,7 +373,6 @@ msgid "Create"
msgstr "יצירה"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Insert"
msgstr "הוסף הנפשה"
@@ -400,9 +399,8 @@ msgid "Change Animation Step"
msgstr "ניקוי ההנפשה"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Rearrange Tracks"
-msgstr "סידור רצועות"
+msgstr "סדר רצועות מחדש"
#: editor/animation_track_editor.cpp
msgid "Transform tracks only apply to Spatial-based nodes."
@@ -478,9 +476,8 @@ msgid "Anim Move Keys"
msgstr ""
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Clipboard is empty"
-msgstr "לוח גזירי המש××‘×™× ×¨×™×§!"
+msgstr "לוח העתקה ריק"
#: editor/animation_track_editor.cpp
#, fuzzy
@@ -541,7 +538,7 @@ msgstr ""
#: editor/animation_track_editor.cpp
msgid "FPS"
-msgstr ""
+msgstr "FPS"
#: editor/animation_track_editor.cpp editor/editor_properties.cpp
#: editor/plugins/polygon_2d_editor_plugin.cpp
@@ -665,7 +662,7 @@ msgstr "הגדרת ×ž×¢×‘×¨×•× ×™× ×ל:"
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
-msgstr "העתקה"
+msgstr "העתק"
#: editor/animation_track_editor.cpp
#, fuzzy
@@ -703,7 +700,7 @@ msgstr "מעבר לשורה"
#: editor/code_editor.cpp
msgid "Line Number:"
-msgstr "מספר השורה:"
+msgstr "שורה מספר:"
#: editor/code_editor.cpp
msgid "%d replaced."
@@ -711,7 +708,7 @@ msgstr "%d הוחלף."
#: editor/code_editor.cpp editor/editor_help.cpp
msgid "%d match."
-msgstr "%d הת×מות."
+msgstr "%d הת×מה."
#: editor/code_editor.cpp editor/editor_help.cpp
msgid "%d matches."
@@ -727,7 +724,7 @@ msgstr "×ž×™×œ×™× ×©×œ×ž×•×ª"
#: editor/code_editor.cpp editor/rename_dialog.cpp
msgid "Replace"
-msgstr "להחליף"
+msgstr "החלף"
#: editor/code_editor.cpp
msgid "Replace All"
@@ -934,9 +931,8 @@ msgid "Edit..."
msgstr "עריכה..."
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Go To Method"
-msgstr "שיטות"
+msgstr "מעבר למתודה"
#: editor/create_dialog.cpp
msgid "Change %s Type"
@@ -1127,7 +1123,7 @@ msgstr "תודה רבה מקהילת Godot!"
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
-msgstr "מתנדבי מנוע Godot"
+msgstr "מתנדבי מנוע גודו"
#: editor/editor_about.cpp
msgid "Project Founders"
@@ -1158,6 +1154,16 @@ msgid "Gold Sponsors"
msgstr "מממני זהב"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "×ª×•×¨×ž×™× ×‘×“×¨×’×ª כסף"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "×ª×•×¨×ž×™× ×‘×“×¨×’×ª ×רד"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "×ž×ž×ž× ×™× ×–×¢×™×¨×™×"
@@ -1212,9 +1218,8 @@ msgid "Error opening package file, not in ZIP format."
msgstr "פתיחת קובץ החבילה נכשלה, המבנה ×ינו zip."
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "%s (Already Exists)"
-msgstr "הפעולה ‚%s’ כבר קיימת!"
+msgstr "%s (כבר ×§×™×™×)"
#: editor/editor_asset_installer.cpp
msgid "Uncompressing Assets"
@@ -1801,13 +1806,11 @@ msgid "Copy Path"
msgstr "העתקת נתיב"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
-#, fuzzy
msgid "Open in File Manager"
-msgstr "הצגה במנהל הקבצי×"
+msgstr "פתיחה במנהל הקבצי×"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
#: editor/filesystem_dock.cpp editor/project_manager.cpp
-#, fuzzy
msgid "Show in File Manager"
msgstr "הצגה במנהל הקבצי×"
@@ -1857,39 +1860,39 @@ msgstr "שמירת קובץ"
#: editor/editor_file_dialog.cpp
msgid "Go Back"
-msgstr "חזרה ×חורה"
+msgstr "מעבר ×חורה"
#: editor/editor_file_dialog.cpp
msgid "Go Forward"
-msgstr "התקדמות קדימה"
+msgstr "מעבר קדימה"
#: editor/editor_file_dialog.cpp
msgid "Go Up"
-msgstr "עלייה למעלה"
+msgstr "מעבר מעלה"
#: editor/editor_file_dialog.cpp
msgid "Toggle Hidden Files"
-msgstr "החלפת מצב תצוגה ×œ×§×‘×¦×™× ×ž×•×¡×ª×¨×™×"
+msgstr "הצג/הסתר ×§×‘×¦×™× ×ž×•×¡×ª×¨×™×"
#: editor/editor_file_dialog.cpp
msgid "Toggle Favorite"
-msgstr "החלפת מצב מועדפי×"
+msgstr "הוספת/ביטול מועדף"
#: editor/editor_file_dialog.cpp
msgid "Toggle Mode"
-msgstr "החלפת מצב"
+msgstr "שינוי מצב"
#: editor/editor_file_dialog.cpp
msgid "Focus Path"
-msgstr "התמקדות על נתיב"
+msgstr "מיקוד נתיב"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Up"
-msgstr "העברת מועדף למעלה"
+msgstr "העברת מועדף מעלה"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Down"
-msgstr "העברת מועדף למטה"
+msgstr "העברת מועדף מטה"
#: editor/editor_file_dialog.cpp
msgid "Go to previous folder."
@@ -1900,18 +1903,16 @@ msgid "Go to next folder."
msgstr "מעבר לתיקיה הב××”."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
-#, fuzzy
msgid "Go to parent folder."
-msgstr "מעבר לתיקייה שמעל"
+msgstr "מעבר לתיקיית העל."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Refresh files."
msgstr "רענן קבצי×."
#: editor/editor_file_dialog.cpp
-#, fuzzy
msgid "(Un)favorite current folder."
-msgstr "×œ× × ×™×ª×Ÿ ליצור תיקייה."
+msgstr "(בטל) העדפת תיקייה נוכחית."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Toggle the visibility of hidden files."
@@ -1951,11 +1952,11 @@ msgstr "סריקת מקורות"
msgid ""
"There are multiple importers for different types pointing to file %s, import "
"aborted"
-msgstr ""
+msgstr "יש מספר מייב××™× ×œ×¡×•×’×™× ×©×•× ×™× ×”×ž×¦×‘×™×¢×™× ×œ×§×•×‘×¥ %s, ×”×™×™×‘×•× ×‘×•×˜×œ"
#: editor/editor_file_system.cpp
msgid "(Re)Importing Assets"
-msgstr ""
+msgstr "×™×™×‘×•× ×ž×©××‘×™× (מחדש)"
#: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp
msgid "Top"
@@ -1975,14 +1976,12 @@ msgid "Inherited by:"
msgstr "מוריש ×ל:"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Description"
-msgstr "תי×ור:"
+msgstr "תי×ור"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Online Tutorials"
-msgstr "×ž×¡×ž×›×™× ×ž×§×•×•× ×™×"
+msgstr "הדרכות מקוונות"
#: editor/editor_help.cpp
msgid "Properties"
@@ -1990,21 +1989,19 @@ msgstr "מ×פייני×"
#: editor/editor_help.cpp
msgid "override:"
-msgstr ""
+msgstr "דריסה:"
#: editor/editor_help.cpp
-#, fuzzy
msgid "default:"
-msgstr "טעינת בררת המחדל"
+msgstr "ברירת מחדל:"
#: editor/editor_help.cpp
msgid "Methods"
-msgstr "שיטות"
+msgstr "מתודות"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Theme Properties"
-msgstr "מ×פייני×"
+msgstr "מ×פייני ערכת עיצוב"
#: editor/editor_help.cpp
msgid "Enumerations"
@@ -2015,31 +2012,32 @@ msgid "Constants"
msgstr "קבועי×"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Property Descriptions"
-msgstr "תי×ור המ×פיין:"
+msgstr "תי×ורי מ×פייני×"
#: editor/editor_help.cpp
-#, fuzzy
msgid "(value)"
-msgstr "ערך:"
+msgstr "(ערך)"
#: editor/editor_help.cpp
msgid ""
"There is currently no description for this property. Please help us by "
"[color=$color][url=$url]contributing one[/url][/color]!"
msgstr ""
+"כרגע ×ין תי×ור למ×פיין ×–×”. בבקשה עזור לנו על-ידי [/color][/url]כתיבת "
+"תי×ור[url=$url][color=$color]!"
#: editor/editor_help.cpp
-#, fuzzy
msgid "Method Descriptions"
-msgstr "תי×ור השיטה:"
+msgstr "תי×ורי מתודות"
#: editor/editor_help.cpp
msgid ""
"There is currently no description for this method. Please help us by [color="
"$color][url=$url]contributing one[/url][/color]!"
msgstr ""
+"כרגע ×ין תי×ור למתודה זו. בבקשה עזור לנו על-ידי [/url][/color]כתיבת תי×ור "
+"[color=$color][url=$url]!"
#: editor/editor_help_search.cpp editor/editor_node.cpp
#: editor/plugins/script_editor_plugin.cpp
@@ -2051,99 +2049,84 @@ msgid "Case Sensitive"
msgstr "תלוי רישיות"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Show Hierarchy"
-msgstr "חיפוש"
+msgstr "הצג היררכיה"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Display All"
-msgstr "הצגה נורמלית"
+msgstr "הצג הכל"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Classes Only"
-msgstr "מחלקות"
+msgstr "מחלקות בלבד"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Methods Only"
-msgstr "שיטות"
+msgstr "מתודות בלבד"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Signals Only"
-msgstr "×ותות"
+msgstr "×ותות בלבד"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Constants Only"
-msgstr "קבועי×"
+msgstr "×§×‘×•×¢×™× ×‘×œ×‘×“"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Properties Only"
-msgstr "מ×פייני×"
+msgstr "מ××¤×™×™× ×™× ×‘×œ×‘×“"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Theme Properties Only"
-msgstr "מ×פייני×"
+msgstr "מ×פייני ערכת עיצוב בלבד"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Member Type"
-msgstr "חברי×"
+msgstr "סוג שדה"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Class"
-msgstr "מחלקה:"
+msgstr "מחלקה"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Method"
-msgstr "שיטות"
+msgstr "מתודה"
#: editor/editor_help_search.cpp editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Signal"
-msgstr "×ותות"
+msgstr "×ות"
#: editor/editor_help_search.cpp editor/plugins/theme_editor_plugin.cpp
msgid "Constant"
msgstr "קבוע"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Property"
-msgstr "מ×פייני×"
+msgstr "מ×פיין"
#: editor/editor_help_search.cpp
-#, fuzzy
msgid "Theme Property"
-msgstr "מ×פייני×"
+msgstr "מ×פיין ערכת עיצוב"
#: editor/editor_inspector.cpp editor/project_settings_editor.cpp
msgid "Property:"
-msgstr ""
+msgstr "מ×פיין:"
#: editor/editor_inspector.cpp
msgid "Set"
-msgstr ""
+msgstr "קבע"
#: editor/editor_inspector.cpp
msgid "Set Multiple:"
-msgstr ""
+msgstr "קביעה מרובה:"
#: editor/editor_log.cpp
msgid "Output:"
msgstr "פלט:"
#: editor/editor_log.cpp editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Copy Selection"
-msgstr "הסרת הבחירה"
+msgstr "העתקת בחירה"
#: editor/editor_log.cpp editor/editor_network_profiler.cpp
#: editor/editor_profiler.cpp editor/editor_properties.cpp
@@ -2153,11 +2136,11 @@ msgstr "הסרת הבחירה"
#: modules/gdnative/gdnative_library_editor_plugin.cpp scene/gui/line_edit.cpp
#: scene/gui/text_edit.cpp
msgid "Clear"
-msgstr "מחיקה"
+msgstr "ניקוי"
#: editor/editor_log.cpp
msgid "Clear Output"
-msgstr "מחיקת הפלט"
+msgstr "ניקוי פלט"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
#: editor/editor_profiler.cpp
@@ -2167,20 +2150,19 @@ msgstr "עצירה"
#: editor/editor_network_profiler.cpp editor/editor_profiler.cpp
#: editor/plugins/animation_state_machine_editor.cpp editor/rename_dialog.cpp
msgid "Start"
-msgstr ""
+msgstr "התחלה"
#: editor/editor_network_profiler.cpp
msgid "%s/s"
-msgstr ""
+msgstr "%s לשנייה"
#: editor/editor_network_profiler.cpp
-#, fuzzy
msgid "Down"
msgstr "הורדה"
#: editor/editor_network_profiler.cpp
msgid "Up"
-msgstr ""
+msgstr "העל××”"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
msgid "Node"
@@ -2188,32 +2170,32 @@ msgstr "מפרק"
#: editor/editor_network_profiler.cpp
msgid "Incoming RPC"
-msgstr ""
+msgstr "RPC נכנס"
#: editor/editor_network_profiler.cpp
msgid "Incoming RSET"
-msgstr ""
+msgstr "RSET נכנס"
#: editor/editor_network_profiler.cpp
msgid "Outgoing RPC"
-msgstr ""
+msgstr "RPC יוצ×"
#: editor/editor_network_profiler.cpp
msgid "Outgoing RSET"
-msgstr ""
+msgstr "RSET יוצ×"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "New Window"
-msgstr ""
+msgstr "חלון חדש"
#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
-msgstr ""
+msgstr "מש××‘×™× ×ž×™×•×‘××™× ×œ× × ×©×ž×¨×•."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: scene/gui/dialogs.cpp
msgid "OK"
-msgstr ""
+msgstr "×ישור"
#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Error saving resource!"
@@ -2224,6 +2206,7 @@ msgid ""
"This resource can't be saved because it does not belong to the edited scene. "
"Make it unique first."
msgstr ""
+"המש×ב ×œ× ×™×›×•×œ להישמר מפני ש×ינו שייך לסצנה שנערכה, הפוך ×ותו ×§×•×“× ×œ×™×™×—×•×“×™."
#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Save Resource As..."
@@ -2235,7 +2218,7 @@ msgstr "×œ× × ×™×ª×Ÿ לפתוח קובץ לכתיבה:"
#: editor/editor_node.cpp
msgid "Requested file format unknown:"
-msgstr "תבנית הקובץ המבוקשת ×œ× ×™×“×•×¢×”:"
+msgstr "סוג הקובץ המבוקש ×œ× ×™×“×•×¢:"
#: editor/editor_node.cpp
msgid "Error while saving."
@@ -2243,27 +2226,27 @@ msgstr "שגי××” בעת השמירה."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
msgid "Can't open '%s'. The file could have been moved or deleted."
-msgstr ""
+msgstr "×œ× ×™×›×•×œ לפתוח ×ת 's%'. יכול להיות שהקובץ הועבר ×ו נמחק."
#: editor/editor_node.cpp
msgid "Error while parsing '%s'."
-msgstr "הפענוח של ‚%s’ נכשל."
+msgstr "שגי××” בפענוח 's%'."
#: editor/editor_node.cpp
msgid "Unexpected end of file '%s'."
-msgstr "סוף הקובץ בלתי צפוי ‚%s’."
+msgstr "סוף קובץ בלתי צפוי '%s'."
#: editor/editor_node.cpp
msgid "Missing '%s' or its dependencies."
-msgstr ""
+msgstr "חסר 's%' ×ו תלות שלו."
#: editor/editor_node.cpp
msgid "Error while loading '%s'."
-msgstr "הטעינה של ‚%s’ נכשלה."
+msgstr "שגי××” בטעינת 's%'."
#: editor/editor_node.cpp
msgid "Saving Scene"
-msgstr "הסצנה נשמרת"
+msgstr "שומר סצנה"
#: editor/editor_node.cpp
msgid "Analyzing"
@@ -2271,7 +2254,7 @@ msgstr "מתבצע ניתוח"
#: editor/editor_node.cpp
msgid "Creating Thumbnail"
-msgstr "נוצרת תמונה ממוזערת"
+msgstr "יצירת תמונה ממוזערת"
#: editor/editor_node.cpp
msgid "This operation can't be done without a tree root."
@@ -2282,34 +2265,34 @@ msgid ""
"This scene can't be saved because there is a cyclic instancing inclusion.\n"
"Please resolve it and then attempt to save again."
msgstr ""
+"סצנה זו ×œ× ×™×›×•×œ×” להישמר מפני שיש הכללת מופע מעגלית.\n"
+"בבקשה פתור ×–×ת ו××– נסה לשמור שוב."
#: editor/editor_node.cpp
msgid ""
"Couldn't save scene. Likely dependencies (instances or inheritance) couldn't "
"be satisfied."
-msgstr ""
-"×œ× × ×™×ª×Ÿ לשמור ×ת הסצנה. כפי הנר××” עקב תלויות (×ž×•×¤×¢×™× ×ו ירושות) ש×ינן "
-"מסופקות."
+msgstr "×œ× × ×™×ª×Ÿ לשמור ×ת הסצנה. כנר××” עקב תלות (מופע ×ו ירושה) ×©×œ× ×ž×¡×•×¤×§×ª."
#: editor/editor_node.cpp editor/scene_tree_dock.cpp
msgid "Can't overwrite scene that is still open!"
-msgstr ""
+msgstr "×œ× × ×™×ª×Ÿ להחליף סצנה שעדיין פתוחה!"
#: editor/editor_node.cpp
msgid "Can't load MeshLibrary for merging!"
-msgstr ""
+msgstr "×œ× × ×™×ª×Ÿ לטעון ×ת MeshLibrary למיזוג!"
#: editor/editor_node.cpp
msgid "Error saving MeshLibrary!"
-msgstr ""
+msgstr "שגי××” בשמירת MeshLibrary!"
#: editor/editor_node.cpp
msgid "Can't load TileSet for merging!"
-msgstr ""
+msgstr "×œ× × ×™×ª×Ÿ לטעון TileSet למיזוג!"
#: editor/editor_node.cpp
msgid "Error saving TileSet!"
-msgstr ""
+msgstr "שגי××” בשמירת TileSet!"
#: editor/editor_node.cpp
msgid "Error trying to save layout!"
@@ -2317,7 +2300,7 @@ msgstr "שמירת הפריסה נכשלה!"
#: editor/editor_node.cpp
msgid "Default editor layout overridden."
-msgstr "בררת המחדל של פריסת העורך שוכתבה."
+msgstr "ברירת המחדל של עורך הפריסה נדרסה."
#: editor/editor_node.cpp
msgid "Layout name not found!"
@@ -2325,7 +2308,7 @@ msgstr "×©× ×”×¤×¨×™×¡×” ×œ× × ×ž×¦×!"
#: editor/editor_node.cpp
msgid "Restored default layout to base settings."
-msgstr "פריסת בררת המחדל שוחזרה להגדרות הבסיס."
+msgstr "פריסת ברירת המחדל שוחזרה להגדרות הבסיס."
#: editor/editor_node.cpp
msgid ""
@@ -2333,20 +2316,24 @@ msgid ""
"Please read the documentation relevant to importing scenes to better "
"understand this workflow."
msgstr ""
+"מש×ב ×–×” שייך לסצנה שיוב××” ×•×œ× × ×™×ª×Ÿ לעריכה.\n"
+"בבקשה קר×/×™ ×ת התיעוד הקשור ×œ×™×™×‘×•× ×¡×¦× ×•×ª כדי להבין טוב יותר ×ת שיטת עבודה."
#: editor/editor_node.cpp
msgid ""
"This resource belongs to a scene that was instanced or inherited.\n"
"Changes to it won't be kept when saving the current scene."
msgstr ""
+"מש×ב ×–×” שייך לסצנה שנוצר לה מופע ×ו שעברה ירושה.\n"
+"×©×™× ×•×™×™× ×‘×ž×©×ב ×œ× ×™×™×©×ž×¨×• בשמירת הסצינה הנוכחית."
#: editor/editor_node.cpp
msgid ""
"This resource was imported, so it's not editable. Change its settings in the "
"import panel and then re-import."
msgstr ""
-"מש×ב ×–×” עבר יבו×, לכן ×ין ×פשרות לערוך ×ותו. יש לשנות ×ת ההגדרות שלו בחלונית "
-"×”×™×™×‘×•× ×•××– ×œ×™×™×‘× ×©×•×‘."
+"מש×ב ×–×” ×ž×™×•×‘× ×•×ין ×פשרות לערוך ×ותו. יש לשנות ×ת הגדרותיו בחלון ×”×™×™×‘×•× "
+"×•×œ×™×™×‘× ×ž×—×“×©."
#: editor/editor_node.cpp
msgid ""
@@ -2355,6 +2342,9 @@ msgid ""
"Please read the documentation relevant to importing scenes to better "
"understand this workflow."
msgstr ""
+"סצנה זו מיוב×ת, כל שינוי בה ×œ× ×™×™×©×ž×¨.\n"
+"יצירת מופע ×ו ירושה ת×פשר לעשות בה שינויי×.\n"
+"בבקשה קר×/×™ ×ת התיעוד הקשור ×œ×™×™×‘×•× ×¡×¦× ×•×ª כדי להבין טוב יותר ×ת שיטת העבודה."
#: editor/editor_node.cpp
msgid ""
@@ -2362,6 +2352,8 @@ msgid ""
"Please read the documentation relevant to debugging to better understand "
"this workflow."
msgstr ""
+"זהו ×ובייקט מרוחק לכן ×©×™× ×•×™×™× ×‘×• ×œ× ×™×™×©×ž×¨×•.\n"
+"בבקשה קר×/×™ ×ת התיועד הקשור לניפוי שגי×ות כדי להבין טוב יותר ×ת שיטת העבודה."
#: editor/editor_node.cpp
msgid "There is no defined scene to run."
@@ -2380,9 +2372,8 @@ msgid "Open Base Scene"
msgstr "פתיחת סצנת בסיס"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Quick Open..."
-msgstr "פתיחת סצנה מהירה…"
+msgstr "פתיחה מהירה…"
#: editor/editor_node.cpp
msgid "Quick Open Scene..."
@@ -2398,16 +2389,15 @@ msgstr "שמירה וסגירה"
#: editor/editor_node.cpp
msgid "Save changes to '%s' before closing?"
-msgstr "לשמור ×ת ×”×©×™× ×•×™×™× ×œÖ¾â€š%s’ לפני הסגירה?"
+msgstr "לשמור ×ת ×”×©×™× ×•×™×™× ×œÖ¾'%s' לפני הסגירה?"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Saved %s modified resource(s)."
-msgstr "טעינת המש×ב נכשלה."
+msgstr "נשמרו %s מש××‘×™× ×©×”×©×ª× ×•."
#: editor/editor_node.cpp
msgid "A root node is required to save the scene."
-msgstr ""
+msgstr "מפרק עליון דרוש כדי לשמור ×ת הסצינה."
#: editor/editor_node.cpp
msgid "Save Scene As..."
@@ -2431,7 +2421,7 @@ msgstr "×œ× × ×™×ª×Ÿ לבצע פעולה זו ×œ×œ× ×¡×¦× ×”."
#: editor/editor_node.cpp
msgid "Export Mesh Library"
-msgstr ""
+msgstr "×™×™×¦×•× Mesh Library"
#: editor/editor_node.cpp
msgid "This operation can't be done without a root node."
@@ -2439,7 +2429,7 @@ msgstr "×œ× × ×™×ª×Ÿ לבצע פעולה זו ×œ×œ× ×ž×¤×¨×§ עליון."
#: editor/editor_node.cpp
msgid "Export Tile Set"
-msgstr ""
+msgstr "×™×™×¦×•× Tile Set"
#: editor/editor_node.cpp
msgid "This operation can't be done without a selected node."
@@ -2454,19 +2444,20 @@ msgid "Can't reload a scene that was never saved."
msgstr "×œ× × ×™×ª×Ÿ לרענן סצנה ×©×ž×¢×•×œ× ×œ× × ×©×ž×¨×”."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reload Saved Scene"
-msgstr "שמירת סצנה"
+msgstr "טעינה מחדש של סצינה שמורה"
#: editor/editor_node.cpp
msgid ""
"The current scene has unsaved changes.\n"
"Reload the saved scene anyway? This action cannot be undone."
msgstr ""
+"הסצינה הנוכחית כוללת ×©×™× ×•×™×™× ×©×œ× × ×©×ž×¨×•.\n"
+"×”×× ×œ×˜×¢×•×Ÿ מחדש ×ת הסצינה? ×œ× × ×™×ª×Ÿ לבטל פעולה זו."
#: editor/editor_node.cpp
msgid "Quick Run Scene..."
-msgstr ""
+msgstr "הפעלה מהירה של הסצנה..."
#: editor/editor_node.cpp
msgid "Quit"
@@ -2509,56 +2500,61 @@ msgid "Close Scene"
msgstr "סגירת סצנה"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reopen Closed Scene"
-msgstr "סגירת סצנה"
+msgstr "פתיחה מחדש של סצנה סגורה"
#: editor/editor_node.cpp
msgid "Unable to enable addon plugin at: '%s' parsing of config failed."
-msgstr "×œ× × ×™×ª×Ÿ לפתוח ×ת תוסף ההרחבות תחת: ‚%s’ פענוח ההגדרות נכשל."
+msgstr "×œ× × ×™×ª×Ÿ לפתוח ×ת תוסף ההרחבות בנתיב: '%s' פענוח ההגדרות נכשל."
#: editor/editor_node.cpp
msgid "Unable to find script field for addon plugin at: 'res://addons/%s'."
-msgstr "×œ× × ×™×ª×Ÿ ×œ×ž×¦×•× ×©×“×” סקריפט עבור תוסף הרחבה תחת ‚res://addons/%s’."
+msgstr "×œ× × ×™×ª×Ÿ ×œ×ž×¦×•× ×©×“×” סקריפט עבור תוסף הרחבה בנתיב 'res://addons/%s'."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s'."
-msgstr "×œ× × ×™×ª×Ÿ לטעון סקריפט הרחבה מהנתיב: ‚%s’."
+msgstr "×œ× × ×™×ª×Ÿ לטעון סקריפט הרחבה מנתיב: '%s'."
#: editor/editor_node.cpp
msgid ""
"Unable to load addon script from path: '%s' There seems to be an error in "
"the code, please check the syntax."
msgstr ""
+"×œ× × ×™×ª×Ÿ לטעון סקריפט הרחבה מנתיב: '%s' נר××” שיש שגי××” בקוד, ×× × ×‘×“×•×§ ×ת "
+"התחביר."
#: editor/editor_node.cpp
msgid ""
"Unable to load addon script from path: '%s' Base type is not EditorPlugin."
-msgstr ""
+msgstr "×œ× × ×™×ª×Ÿ לטעון סקריפט הרחבה מנתיב: '%s' סוג הבסיס ×ינו EditorPlugin."
#: editor/editor_node.cpp
msgid "Unable to load addon script from path: '%s' Script is not in tool mode."
-msgstr ""
+msgstr "×œ× × ×™×ª×Ÿ לטעון סקריפט הרחבה מנתיב: '%s' סקריפט ×ינו מוגדר ככלי (tool)."
#: editor/editor_node.cpp
msgid ""
"Scene '%s' was automatically imported, so it can't be modified.\n"
"To make changes to it, a new inherited scene can be created."
msgstr ""
+"הסצינה '%s' יוב××” ב×ופן ×וטומטי ו×ין ×פשרות לשנות ×ותה.\n"
+"כדי לבצע בה שינויי×, ניתן ליצור סצינה חדשה בירושה."
#: editor/editor_node.cpp
msgid ""
"Error loading scene, it must be inside the project path. Use 'Import' to "
"open the scene, then save it inside the project path."
msgstr ""
+"שגי××” בטעינת הסצנה, ×”×™× ×—×™×™×‘×ª להיות בתוך נתיב המיז×. השתמש ב'ייבו×' כדי "
+"לפתוח ×ת הסצינה, ו××– שמור ×ותה בנתיב המיז×."
#: editor/editor_node.cpp
msgid "Scene '%s' has broken dependencies:"
-msgstr ""
+msgstr "לסצינה '%s' יש תלות חסרה:"
#: editor/editor_node.cpp
msgid "Clear Recent Scenes"
-msgstr ""
+msgstr "× ×§×” סצינות ×חרונות"
#: editor/editor_node.cpp
msgid ""
@@ -2566,6 +2562,8 @@ msgid ""
"You can change it later in \"Project Settings\" under the 'application' "
"category."
msgstr ""
+"×œ× ×”×•×’×“×¨×” סצנה ר×שית, לבחור ×חת?\n"
+"×פשר לשנות ×–×ת מ×וחר יותר ב-\"הגדרות מיז×\" תחת הקטגוריה 'יישו×'."
#: editor/editor_node.cpp
msgid ""
@@ -2573,6 +2571,8 @@ msgid ""
"You can change it later in \"Project Settings\" under the 'application' "
"category."
msgstr ""
+"הסצינה שנבחרה '%s' ×œ× ×§×™×™×ž×ª, לבחור סצנה קיימת?\n"
+"×פשר לשנות ×–×ת מ×וחר יותר ב\"הגדרות מיז×\" תחת הקטגוריה 'יישו×'."
#: editor/editor_node.cpp
msgid ""
@@ -2580,81 +2580,78 @@ msgid ""
"You can change it later in \"Project Settings\" under the 'application' "
"category."
msgstr ""
+"הסצינה שנבחרה '%s' ××™× ×” קובץ סצינה, לבחור קובץ סצינה ×חר?\n"
+"×פשר לשנות ×–×ת מ×וחר יותר ב-\"הגדרות מיז×\" תחת הקטגוריה 'יישו×'."
#: editor/editor_node.cpp
msgid "Save Layout"
-msgstr ""
+msgstr "שמירת פריסה"
#: editor/editor_node.cpp
msgid "Delete Layout"
-msgstr ""
+msgstr "מחיקת פריסה"
#: editor/editor_node.cpp editor/import_dock.cpp
#: editor/script_create_dialog.cpp
msgid "Default"
-msgstr ""
+msgstr "בחירת מחדל"
#: editor/editor_node.cpp editor/editor_properties.cpp
#: editor/plugins/script_editor_plugin.cpp editor/property_editor.cpp
-#, fuzzy
msgid "Show in FileSystem"
-msgstr "הצגה במערכת הקבצי×"
+msgstr "הצגה בחלון הקבצי×"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Play This Scene"
-msgstr "נגינת הסצנה"
+msgstr "הרצת הסצנה"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Close Tab"
-msgstr "לסגור לשוניות ×חרות"
+msgstr "סגירת לשונית"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Undo Close Tab"
-msgstr "לסגור לשוניות ×חרות"
+msgstr "ביטול סגירת לשונית"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
msgid "Close Other Tabs"
-msgstr "לסגור לשוניות ×חרות"
+msgstr "סגירת לשוניות ×חרות"
#: editor/editor_node.cpp
msgid "Close Tabs to the Right"
-msgstr ""
+msgstr "סגירת לשוניות מימין"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Close All Tabs"
-msgstr "לסגור הכול"
+msgstr "סגירת כל הלשוניות"
#: editor/editor_node.cpp
msgid "Switch Scene Tab"
-msgstr ""
+msgstr "החלפת לשונית סצנה"
#: editor/editor_node.cpp
msgid "%d more files or folders"
-msgstr ""
+msgstr "%d ×§×‘×¦×™× ×ו תיקיות נוספי×"
#: editor/editor_node.cpp
msgid "%d more folders"
-msgstr ""
+msgstr "%d תיקיות נוספות"
#: editor/editor_node.cpp
msgid "%d more files"
-msgstr ""
+msgstr "%d ×§×‘×¦×™× × ×•×¡×¤×™×"
#: editor/editor_node.cpp
msgid "Dock Position"
-msgstr ""
+msgstr "×ž×™×§×•× ×”×¤× ×œ"
#: editor/editor_node.cpp
msgid "Distraction Free Mode"
-msgstr ""
+msgstr "מצב ×œ×œ× ×”×¡×—×•×ª דעת"
#: editor/editor_node.cpp
msgid "Toggle distraction-free mode."
-msgstr ""
+msgstr "הפעל/בטל מצב ×œ×œ× ×”×¡×—×•×ª דעת."
#: editor/editor_node.cpp
msgid "Add a new scene."
@@ -2666,12 +2663,11 @@ msgstr "סצנה"
#: editor/editor_node.cpp
msgid "Go to previously opened scene."
-msgstr "מעבר לסצנה שנפתחה ×§×•×“× ×œ×›×Ÿ."
+msgstr "מעבר לסצנה הקודמת."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Copy Text"
-msgstr "העתקת נתיב"
+msgstr "העתקת טקסט"
#: editor/editor_node.cpp
msgid "Next tab"
@@ -2683,7 +2679,7 @@ msgstr "הלשונית הקודמת"
#: editor/editor_node.cpp
msgid "Filter Files..."
-msgstr ""
+msgstr "סנן קבצי×..."
#: editor/editor_node.cpp
msgid "Operations with scene files."
@@ -2710,7 +2706,6 @@ msgid "Save Scene"
msgstr "שמירת סצנה"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Save All Scenes"
msgstr "שמירת כל הסצנות"
@@ -2720,11 +2715,11 @@ msgstr "המרה ×ל…"
#: editor/editor_node.cpp
msgid "MeshLibrary..."
-msgstr ""
+msgstr "MeshLibrary..."
#: editor/editor_node.cpp
msgid "TileSet..."
-msgstr ""
+msgstr "TileSet..."
#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
@@ -2750,17 +2745,16 @@ msgid "Project Settings..."
msgstr "הגדרות מיז×..."
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Version Control"
-msgstr "גרסה:"
+msgstr "בקרת גירס×ות"
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Set Up Version Control"
-msgstr ""
+msgstr "קביעת בקרת גירס×ות"
#: editor/editor_node.cpp
msgid "Shut Down Version Control"
-msgstr ""
+msgstr "סגור בקרת גירס×ות"
#: editor/editor_node.cpp
msgid "Export..."
@@ -2768,7 +2762,7 @@ msgstr "ייצו×..."
#: editor/editor_node.cpp
msgid "Install Android Build Template..."
-msgstr ""
+msgstr "התקנת תבנית בנייה ל×נדרו×יד..."
#: editor/editor_node.cpp
msgid "Open Project Data Folder"
@@ -2784,7 +2778,7 @@ msgstr "סייר מש××‘×™× ×™×ª×•×ž×™× ..."
#: editor/editor_node.cpp
msgid "Quit to Project List"
-msgstr "יצי××” לרשימת המיזמי×"
+msgstr "יצי××” לרשימת מיזמי×"
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: editor/project_export.cpp
@@ -2816,16 +2810,22 @@ msgid ""
"On Android, deploy will use the USB cable for faster performance. This "
"option speeds up testing for games with a large footprint."
msgstr ""
+"×›×שר ×פשרות זו מופעלת, ×™×™×¦×•× ×ו פריסה יפיקו קובץ הפעלה מינימלי.\n"
+"מערכת ×”×§×‘×¦×™× ×ª×¡×•×¤×§ ×ž×”×ž×™×–× ×¢×œ ידי העורך ברשת.\n"
+"ב×נדרו×יד, הפריסה תשתמש בכבל USB ×œ×‘×™×¦×•×¢×™× ×ž×”×™×¨×™× ×™×•×ª×¨. ×פשרות זו מזרזת בדיקה "
+"של ×ž×©×—×§×™× ×¢× ×§×•×‘×¥ הרצה גדול."
#: editor/editor_node.cpp
msgid "Visible Collision Shapes"
-msgstr ""
+msgstr "צורות התנגשות גלויי×"
#: editor/editor_node.cpp
msgid ""
"Collision shapes and raycast nodes (for 2D and 3D) will be visible on the "
"running game if this option is turned on."
msgstr ""
+"צורות התנגשויות ומפרקי ×§×¨× ×™×™× (עבור דו ותלת מימד) יהיו ×’×œ×•×™×™× ×‘×”×¨×¦×ª המשחק ×× "
+"×פשרות ×–×ת מופעלת."
#: editor/editor_node.cpp
msgid "Visible Navigation"
@@ -2835,7 +2835,7 @@ msgstr "ניווט גלוי"
msgid ""
"Navigation meshes and polygons will be visible on the running game if this "
"option is turned on."
-msgstr ""
+msgstr "רשתות ניווט ×•×ž×¦×•×œ×¢×™× ×™×”×™×• ×’×œ×•×™×™× ×‘×”×¨×¦×ª המשחק ×× ×פשרות ×–×ת מופעלת."
#: editor/editor_node.cpp
msgid "Sync Scene Changes"
@@ -2848,6 +2848,8 @@ msgid ""
"When used remotely on a device, this is more efficient with network "
"filesystem."
msgstr ""
+"×›×שר ×פשרות זו מופעלת, כל ×”×©×™× ×•×™×™× ×©×™×‘×•×¦×¢×• בסצנה בעורך יוצגו בהרצת המשחק.\n"
+"בשימוש ×¢× ×ž×›×©×™×¨ מרוחק, מערכת ×§×‘×¦×™× ×‘×¨×©×ª (NFS) תהיה יעילה יותר ."
#: editor/editor_node.cpp
msgid "Sync Script Changes"
@@ -2860,6 +2862,8 @@ msgid ""
"When used remotely on a device, this is more efficient with network "
"filesystem."
msgstr ""
+"×›×שר ×פשרות זו מופעלת, כל סקריפט שנשמר יטען מחדש בהרצת המשחק.\n"
+"בשימוש ×¢× ×ž×›×©×™×¨ מרוחק, מערכת ×§×‘×¦×™× ×‘×¨×©×ª (NFS) תהיה יעילה יותר ."
#: editor/editor_node.cpp editor/script_create_dialog.cpp
msgid "Editor"
@@ -2874,46 +2878,40 @@ msgid "Editor Layout"
msgstr "פריסת עורך"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Take Screenshot"
-msgstr "שמירת סצנה"
+msgstr "שמירת ×¦×™×œ×•× ×ž×¡×š"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Screenshots are stored in the Editor Data/Settings Folder."
-msgstr "הגדרות עורך"
+msgstr "צילומי מסך × ×©×ž×¨×™× ×‘×ª×™×§×™×™×ª נתוני/הגדרות העורך."
#: editor/editor_node.cpp
msgid "Toggle Fullscreen"
-msgstr "כניסה ×ל/יצי××” ממסך מל×"
+msgstr "הפעלת/ביטול מסך מל×"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Toggle System Console"
-msgstr "החלפת מצב"
+msgstr "הפעלת/ביטול מסוף מערכת"
#: editor/editor_node.cpp
msgid "Open Editor Data/Settings Folder"
-msgstr "פתח תיקיית נתוני×/הגדרות של העורך"
+msgstr "פתיחת תיקיית נתוני/הגדרות העורך"
#: editor/editor_node.cpp
msgid "Open Editor Data Folder"
-msgstr ""
+msgstr "פתיחת תיקיית נתוני העורך"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Open Editor Settings Folder"
-msgstr "הגדרות עורך"
+msgstr "פתיחת תיקיית הגדרות העורך"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Manage Editor Features..."
-msgstr "ניהול תבניות ייצו×"
+msgstr "ניהול תכונות העורך..."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Manage Export Templates..."
-msgstr "ניהול תבניות ייצו×"
+msgstr "ניהול תבניות ייצו×..."
#: editor/editor_node.cpp editor/plugins/shader_editor_plugin.cpp
msgid "Help"
@@ -2938,13 +2936,12 @@ msgid "Q&A"
msgstr "ש×לות ותשובות נפוצות"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Report a Bug"
-msgstr "×™×™×‘×•× ×ž×—×“×©"
+msgstr "דיווח על תקלה (ב××’)"
#: editor/editor_node.cpp
msgid "Send Docs Feedback"
-msgstr ""
+msgstr "שליחת משוב על התיעוד"
#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp
msgid "Community"
@@ -2952,19 +2949,19 @@ msgstr "קהילה"
#: editor/editor_node.cpp
msgid "About"
-msgstr "על"
+msgstr "על ×ודות"
#: editor/editor_node.cpp
msgid "Play the project."
-msgstr "נגינת המיז×…"
+msgstr "הרצת המיז×."
#: editor/editor_node.cpp
msgid "Play"
-msgstr "× ×’×™× ×”"
+msgstr "הרצה"
#: editor/editor_node.cpp
msgid "Pause the scene execution for debugging."
-msgstr ""
+msgstr "הפסקת הרצת הסצנה לניפוי שגי×ות."
#: editor/editor_node.cpp
msgid "Pause Scene"
@@ -2976,49 +2973,44 @@ msgstr "עצירת הסצנה."
#: editor/editor_node.cpp
msgid "Play the edited scene."
-msgstr "נגינת הסצנה שנערכה."
+msgstr "הרצת הסצנה שנערכה."
#: editor/editor_node.cpp
msgid "Play Scene"
-msgstr "נגינת הסצנה"
+msgstr "הרצת הסצנה"
#: editor/editor_node.cpp
msgid "Play custom scene"
-msgstr "נגינת סצנה מות×מת ×ישית"
+msgstr "הרצת סצנה מות×מת ×ישית"
#: editor/editor_node.cpp
msgid "Play Custom Scene"
-msgstr "נגינת סצנה בהת×מה ×ישית"
+msgstr "הרצת סצנה בהת×מה ×ישית"
#: editor/editor_node.cpp
msgid "Changing the video driver requires restarting the editor."
-msgstr ""
+msgstr "שינוי מנהל התקן הוויד×ו דורש הפעלת העורך מחדש."
#: editor/editor_node.cpp editor/project_settings_editor.cpp
#: editor/settings_config_dialog.cpp
-#, fuzzy
msgid "Save & Restart"
-msgstr "לשמור ולצ×ת"
+msgstr "שמירה והפעלה מחדש"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Spins when the editor window redraws."
-msgstr "מסתובב ×›×שר חלון העורך מצויר מחדש!"
+msgstr "מסתובב ×›×שר חלון העורך מצויר מחדש."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Update Continuously"
-msgstr "מתמשך"
+msgstr "עדכון רציף"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Update When Changed"
-msgstr "עדכון שינויי×"
+msgstr "עדכון בעת שינוי"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Hide Update Spinner"
-msgstr "השבתת שבשבת עדכון"
+msgstr "הסתרת מחוון העדכון"
#: editor/editor_node.cpp
msgid "FileSystem"
@@ -3029,9 +3021,8 @@ msgid "Inspector"
msgstr "חוקר"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Expand Bottom Panel"
-msgstr "להרחיב הכול"
+msgstr "הרחבת פ×נל תחתון"
#: editor/editor_node.cpp
msgid "Output"
@@ -3043,12 +3034,11 @@ msgstr "×œ× ×œ×©×ž×•×¨"
#: editor/editor_node.cpp
msgid "Android build template is missing, please install relevant templates."
-msgstr ""
+msgstr "חסרה תבנית בנייה ל×נדרו×יד, × × ×œ×”×ª×§×™×Ÿ תבניות רלוונטיות."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Manage Templates"
-msgstr "ניהול תבניות ייצו×"
+msgstr "ניהול תבניות"
#: editor/editor_node.cpp
msgid ""
@@ -3060,6 +3050,12 @@ msgid ""
"the \"Use Custom Build\" option should be enabled in the Android export "
"preset."
msgstr ""
+"פעולה זו תגדיר ×ת ×”×ž×™×–× ×©×œ×š לבניית ×נדרו×יד מות×מת ×ישית על ידי התקנת תבנית "
+"המקור ל- \"res://android/build\".\n"
+"ל×חר מכן ×פשר להחיל ×©×™× ×•×™×™× ×•×œ×‘× ×•×ª APK מות×× ×ישית ×‘×™×™×¦×•× (הוספת מודולי×, "
+"שינוי AndroidManifest.xml, וכו').\n"
+"כדי לערוך בנייה מות×מת ×ישית ×‘×ž×§×•× ×©×™×ž×•×© בתבנית קיימת, יש ל×פשר ×ת \"השתמש "
+"בבניה מות×מת ×ישית\" בהגדרות ×”×™×™×¦×•× ×œ×נדרו×יד."
#: editor/editor_node.cpp
msgid ""
@@ -3127,9 +3123,8 @@ msgid "Open the previous Editor"
msgstr "פתיחת העורך הקוד×"
#: editor/editor_node.h
-#, fuzzy
msgid "Warning!"
-msgstr "×זהרות"
+msgstr "×זהרה!"
#: editor/editor_path.cpp
msgid "No sub-resources found."
@@ -3596,9 +3591,8 @@ msgid "Download Templates"
msgstr "הורדת תבניות"
#: editor/export_template_manager.cpp
-#, fuzzy
msgid "Select mirror from list: (Shift+Click: Open in Browser)"
-msgstr "בחירת ×תר מר××” מהרשימה: "
+msgstr "בחר ×תר חלופי מהרשימה: (Shift+Click: פתיחה בדפדפן)"
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3663,9 +3657,8 @@ msgid "Duplicating folder:"
msgstr "תיקייה משוכפלת:"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "New Inherited Scene"
-msgstr "סצנה חדשה בירושה…"
+msgstr "סצנה חדשה יורשת"
#: editor/filesystem_dock.cpp
#, fuzzy
@@ -3800,9 +3793,8 @@ msgid "Create Script"
msgstr "יצירת סקריפט"
#: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Find in Files"
-msgstr "×יתור…"
+msgstr "×יתור בקבצי×"
#: editor/find_in_files.cpp
#, fuzzy
@@ -3869,9 +3861,8 @@ msgid "Remove from Group"
msgstr "הסרה מקבוצה"
#: editor/groups_editor.cpp
-#, fuzzy
msgid "Group name already exists."
-msgstr "הפעולה ‚%s’ כבר קיימת!"
+msgstr "×©× ×”×§×‘×•×¦×” כבר ×§×™×™×."
#: editor/groups_editor.cpp
#, fuzzy
@@ -4064,9 +4055,8 @@ msgid "Copy Params"
msgstr "העתקת משתני×"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Edit Resource Clipboard"
-msgstr "לוח גזירי המש××‘×™× ×¨×™×§!"
+msgstr "ערוך לוח העתקת מש×בי×"
#: editor/inspector_dock.cpp
msgid "Copy Resource"
@@ -4308,9 +4298,8 @@ msgid "Open Animation Node"
msgstr "×©× ×”× ×¤×©×” חדשה:"
#: editor/plugins/animation_blend_space_2d_editor.cpp
-#, fuzzy
msgid "Triangle already exists."
-msgstr "הפעולה ‚%s’ כבר קיימת!"
+msgstr "המשולש כבר ×§×™×™×."
#: editor/plugins/animation_blend_space_2d_editor.cpp
#, fuzzy
@@ -4365,14 +4354,13 @@ msgid "Blend:"
msgstr ""
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Parameter Changed"
-msgstr "שינויי חומרי×"
+msgstr "משתנה השתנה"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Edit Filters"
-msgstr ""
+msgstr "עריכת מסנני×"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Output node can't be added to the blend tree."
@@ -4405,15 +4393,14 @@ msgid "Nodes Disconnected"
msgstr "מנותק"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Set Animation"
-msgstr "×©× ×”× ×¤×©×” חדשה:"
+msgstr "קביעת הנפשה"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
#, fuzzy
msgid "Delete Node"
-msgstr "מחיקת שורה"
+msgstr "מחק מפרק"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/scene_tree_dock.cpp
@@ -4508,9 +4495,8 @@ msgid "Remove Animation"
msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "Invalid animation name!"
-msgstr "×©× ×©×’×•×™."
+msgstr "×©× ×”× ×¤×©×” ×œ× ×—×•×§×™!"
#: editor/plugins/animation_player_editor_plugin.cpp
#, fuzzy
@@ -4539,14 +4525,12 @@ msgid "Duplicate Animation"
msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "No animation to copy!"
-msgstr "תקריב הנפשה."
+msgstr "×ין הנפשה להעתקה!"
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "No animation resource on clipboard!"
-msgstr "×œ× ×‘× ×ª×™×‘ המש×ב."
+msgstr "×ין מש×ב הנפשה בלוח ההעתקה!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Pasted Animation"
@@ -4557,9 +4541,8 @@ msgid "Paste Animation"
msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "No animation to edit!"
-msgstr "×©× ×”× ×¤×©×” חדשה:"
+msgstr "×ין הנפשה לעריכה!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Play selected animation backwards from current pos. (A)"
@@ -4702,9 +4685,8 @@ msgid "Move Node"
msgstr "מצב הזזה (W)"
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Transition exists!"
-msgstr "מעברון"
+msgstr "המעברון ×§×™×™×!"
#: editor/plugins/animation_state_machine_editor.cpp
#, fuzzy
@@ -6473,7 +6455,7 @@ msgstr "הזזת נקודה"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid ""
"The skeleton property of the Polygon2D does not point to a Skeleton2D node"
-msgstr ""
+msgstr "מ×פיין 'skeleton' של Polygon2D ×ינו מצביע על מפרק Skeleton2D"
#: editor/plugins/polygon_2d_editor_plugin.cpp
#, fuzzy
@@ -6648,9 +6630,8 @@ msgid "Show Grid"
msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Configure Grid:"
-msgstr "הגדרת הצמדה…"
+msgstr "הגדר רשת:"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid Offset X:"
@@ -7038,9 +7019,8 @@ msgid "Line"
msgstr "שורה:"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Go to Function"
-msgstr "מעבר לפונקציה…"
+msgstr "עבור לפונקציה"
#: editor/plugins/script_text_editor.cpp
msgid "Only resources from filesystem can be dropped."
@@ -8841,9 +8821,8 @@ msgid "Create Shader Node"
msgstr "יצירת תיקייה"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Color function."
-msgstr "מעבר לפונקציה…"
+msgstr "פונקציית צבע."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Color operator."
@@ -9333,9 +9312,8 @@ msgid "Transform uniform."
msgstr "התמרה"
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Vector function."
-msgstr "מעבר לפונקציה…"
+msgstr "פונקציה וקטורית."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector operator."
@@ -10061,9 +10039,8 @@ msgid ""
msgstr ""
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "An action with the name '%s' already exists."
-msgstr "הפעולה ‚%s’ כבר קיימת!"
+msgstr "פעולה ×¢× ×”×©× '%s' כבר קיימת."
#: editor/project_settings_editor.cpp
msgid "Rename Input Action Event"
@@ -10657,7 +10634,6 @@ msgid "Delete %d nodes and any children?"
msgstr "מחיקת שורה"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete %d nodes?"
msgstr "מחק %d מפרקי×?"
@@ -10953,19 +10929,16 @@ msgid "Select a Node"
msgstr ""
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Path is empty."
-msgstr "לוח גזירי המש××‘×™× ×¨×™×§!"
+msgstr "הנתיב ריק."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Filename is empty."
-msgstr "לוח גזירי המש××‘×™× ×¨×™×§!"
+msgstr "×©× ×”×§×•×‘×¥ ריק."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Path is not local."
-msgstr "הנתיב ×œ× ×ž×•×‘×™×œ מפרק!"
+msgstr "הנתיב ×ינו מקומי."
#: editor/script_create_dialog.cpp
#, fuzzy
@@ -11063,9 +11036,8 @@ msgid "Will load an existing script file."
msgstr "טעינת פריסת ×פיקי שמע."
#: editor/script_create_dialog.cpp
-#, fuzzy
msgid "Script file already exists."
-msgstr "הפעולה ‚%s’ כבר קיימת!"
+msgstr "קובץ סקריפט כבר ×§×™×™×."
#: editor/script_create_dialog.cpp
msgid ""
@@ -11642,334 +11614,324 @@ msgid "Done!"
msgstr ""
#: modules/visual_script/visual_script.cpp
+#, fuzzy
msgid ""
"A node yielded without working memory, please read the docs on how to yield "
"properly!"
msgstr ""
+"מפרק ביצע yield ×œ×œ× ×–×™×›×¨×•×Ÿ עבודה, ×× × ×§×¨× ×ת התיעוד על ×יך לעשות yield כר×וי!"
#: modules/visual_script/visual_script.cpp
msgid ""
"Node yielded, but did not return a function state in the first working "
"memory."
-msgstr ""
+msgstr "המפרק ביצע yield, ×בל ×œ× ×”×—×–×™×¨ ×ת מצב הפונקציה בזיכרון העבודה הר×שון."
#: modules/visual_script/visual_script.cpp
msgid ""
"Return value must be assigned to first element of node working memory! Fix "
"your node please."
msgstr ""
+"יש להקצות ×ת הערך המוחזר ל×למנט הר×שון של זיכרון עבודה של המפרק! יש לתקן ×ת "
+"המפרק בבקשה."
#: modules/visual_script/visual_script.cpp
msgid "Node returned an invalid sequence output: "
-msgstr ""
+msgstr "מפרק החזיר פלט סדר (sequence) ×œ× ×—×•×§×™: "
#: modules/visual_script/visual_script.cpp
msgid "Found sequence bit but not the node in the stack, report bug!"
-msgstr ""
+msgstr "סיבית הסדר (sequence bit) נמצ××” ×בל המפרק ×œ× ×‘×ž×—×¡× ×™×ª, דווח על שגי××”!"
#: modules/visual_script/visual_script.cpp
msgid "Stack overflow with stack depth: "
-msgstr ""
+msgstr "גלישת מחסנית ×¢× ×¢×•×ž×§ מחסנית: "
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Signal Arguments"
-msgstr ""
+msgstr "שינוי ××¨×’×•×ž× ×˜×™× ×©×œ ×ות"
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Argument Type"
-msgstr ""
+msgstr "שינוי סוג ×רגומנט"
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Argument name"
-msgstr ""
+msgstr "שינוי ×©× ×רגומנט"
#: modules/visual_script/visual_script_editor.cpp
msgid "Set Variable Default Value"
-msgstr ""
+msgstr "קביעת ערך ברירת מחדל של משתנה"
#: modules/visual_script/visual_script_editor.cpp
msgid "Set Variable Type"
-msgstr ""
+msgstr "קביעת סוג משתנה"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Input Port"
-msgstr "מועדפי×:"
+msgstr "הוספת פורט כניסה"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Output Port"
-msgstr "מועדפי×:"
+msgstr "הוספת פורט יצי××”"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Override an existing built-in function."
-msgstr "×©× ×©×’×•×™. ×œ× ×™×›×•×œ לחפוף ×œ×©× ×¡×•×’ מובנה ×§×™×™×."
+msgstr "דריסה של פונקציה מובנת קיימת."
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Create a new function."
-msgstr "יצירת %s חדש"
+msgstr "יצירת פונקציה חדשה."
#: modules/visual_script/visual_script_editor.cpp
msgid "Variables:"
-msgstr ""
+msgstr "משתני×:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Create a new variable."
-msgstr "יצירת %s חדש"
+msgstr "יצירת משתנה חדש."
#: modules/visual_script/visual_script_editor.cpp
msgid "Signals:"
msgstr "×ותות:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Create a new signal."
-msgstr "יצירת מצולע"
+msgstr "יצירת ×ות חדש."
#: modules/visual_script/visual_script_editor.cpp
msgid "Name is not a valid identifier:"
-msgstr ""
+msgstr "×”×©× ×ינו מזהה חוקי:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Name already in use by another func/var/signal:"
-msgstr ""
+msgstr "×”×©× ×›×‘×¨ בשימוש של פונקציה/משתנה/×ות ×חר:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Rename Function"
-msgstr ""
+msgstr "שינוי ×©× ×¤×•× ×§×¦×™×”"
#: modules/visual_script/visual_script_editor.cpp
msgid "Rename Variable"
-msgstr ""
+msgstr "שינוי ×©× ×ž×©×ª× ×”"
#: modules/visual_script/visual_script_editor.cpp
msgid "Rename Signal"
-msgstr ""
+msgstr "שינוי ×©× ×ות"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Function"
-msgstr ""
+msgstr "הוספת פונקציה"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Delete input port"
-msgstr "הסרת נקודה בנתיב"
+msgstr "מחיקת פורט כניסה"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Variable"
-msgstr ""
+msgstr "הוספת משתנה"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Signal"
-msgstr ""
+msgstr "הוספת ×ות"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Remove Input Port"
-msgstr "הסרת נקודה בנתיב"
+msgstr "הסרת פורט כניסה"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Remove Output Port"
-msgstr "הסרת נקודה בנתיב"
+msgstr "הסרת פורט יצי××”"
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Expression"
-msgstr ""
+msgstr "שינוי ביטוי"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove VisualScript Nodes"
-msgstr ""
+msgstr "הסרת מפרקי VisualScript"
#: modules/visual_script/visual_script_editor.cpp
msgid "Duplicate VisualScript Nodes"
-msgstr ""
+msgstr "שכפול מפרקי VisualScript"
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold %s to drop a Getter. Hold Shift to drop a generic signature."
msgstr ""
+"×”×—×–×§ ×ת %s כדי להוסיף Getter. ×”×—×–×§ ×ת מקש Shift כדי להוסיף חתימה גנרית."
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold Ctrl to drop a Getter. Hold Shift to drop a generic signature."
msgstr ""
+"×”×—×–×§ ×ת מקש Ctrl כדי להוסיף Getter. ×”×—×–×§ ×ת מקש Shift כדי להוסיף חתימה גנרית."
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold %s to drop a simple reference to the node."
-msgstr ""
+msgstr "×”×—×–×§ ×ת %s כדי להוסיף הפניה פשוטה למפרק."
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold Ctrl to drop a simple reference to the node."
-msgstr ""
+msgstr "×”×—×–×§ ×ת מקש Ctrl כדי להוסיף הפניה פשוטה למפרק."
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold %s to drop a Variable Setter."
-msgstr ""
+msgstr "×”×—×–×§ ×ת %s כדי להוסיף Setter למשתנה."
#: modules/visual_script/visual_script_editor.cpp
msgid "Hold Ctrl to drop a Variable Setter."
-msgstr ""
+msgstr "×”×—×–×§ ×ת מקש Ctrl כדי להוסיף  Setter למשתנה."
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Preload Node"
-msgstr ""
+msgstr "הוספת מפרק ×§×“× ×˜×¢×™× ×”"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Node(s) From Tree"
-msgstr ""
+msgstr "הוספת מפרק/×™× ×ž×”×¢×¥"
#: modules/visual_script/visual_script_editor.cpp
msgid ""
"Can't drop properties because script '%s' is not used in this scene.\n"
"Drop holding 'Shift' to just copy the signature."
msgstr ""
+"×œ× × ×™×ª×Ÿ להוסיף מ××¤×™×™× ×™× ×›×™ סקריפט '%s' ×œ× ×‘×©×™×ž×•×© בסצנה זו.\n"
+"החזקת 'Shift' בזמן הוספה תעתיק רק ×ת החתימה."
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Getter Property"
-msgstr ""
+msgstr "הוספת מ×פיין ל-Getter"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Setter Property"
-msgstr ""
+msgstr "הוספת מ×פיין ל-Setter"
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Base Type"
-msgstr ""
+msgstr "שינוי סוג בסיס"
#: modules/visual_script/visual_script_editor.cpp
msgid "Move Node(s)"
-msgstr ""
+msgstr "הזזת מפרק(×™×)"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove VisualScript Node"
-msgstr ""
+msgstr "הסרת מפרק VisualScript"
#: modules/visual_script/visual_script_editor.cpp
msgid "Connect Nodes"
-msgstr ""
+msgstr "חיבור מפרקי×"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Disconnect Nodes"
-msgstr "מנותק"
+msgstr "ניתוק מפרקי×"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Connect Node Data"
-msgstr "התחברות למפרק:"
+msgstr "קישור נתוני ‫מפרק"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Connect Node Sequence"
-msgstr "התחברות למפרק:"
+msgstr "קישור Sequence של מפרק"
#: modules/visual_script/visual_script_editor.cpp
msgid "Script already has function '%s'"
-msgstr ""
+msgstr "לסקריפט יש כבר פונקציה '%s'"
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Input Value"
-msgstr ""
+msgstr "שינוי ערך נקלט"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Resize Comment"
-msgstr "החלפת מצב הערה"
+msgstr "שינוי גודל הערה"
#: modules/visual_script/visual_script_editor.cpp
msgid "Can't copy the function node."
-msgstr ""
+msgstr "×œ× × ×™×ª×Ÿ להעתיק ×ת פונקצית המפרק."
#: modules/visual_script/visual_script_editor.cpp
msgid "Clipboard is empty!"
-msgstr ""
+msgstr "לוח העתקה ריק!"
#: modules/visual_script/visual_script_editor.cpp
msgid "Paste VisualScript Nodes"
-msgstr ""
+msgstr "הדבקת מפרקי VisualScript"
#: modules/visual_script/visual_script_editor.cpp
msgid "Can't create function with a function node."
-msgstr ""
+msgstr "×œ× × ×™×ª×Ÿ ליצור פונקציה ×¢× ×¤×•× ×§×¦×™×ª המפרק."
#: modules/visual_script/visual_script_editor.cpp
msgid "Can't create function of nodes from nodes of multiple functions."
-msgstr ""
+msgstr "×œ× × ×™×ª×Ÿ ליצור פונקציה של ×ž×¤×¨×§×™× ×ž×ž×¤×¨×§×™× ×©×œ פונקציות מרובות."
#: modules/visual_script/visual_script_editor.cpp
msgid "Select at least one node with sequence port."
-msgstr ""
+msgstr "בחר מפרק ×חד לפחות ×¢× ×›× ×™×¡×” רציפה (Sequence)."
#: modules/visual_script/visual_script_editor.cpp
msgid "Try to only have one sequence input in selection."
-msgstr ""
+msgstr "יש לנסות בחירה של רק כניסה רציפה ×חת."
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Create Function"
-msgstr "יצירת %s חדש"
+msgstr "יצירת פונקציה"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove Function"
-msgstr ""
+msgstr "הסרת פונקציה"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove Variable"
-msgstr ""
+msgstr "הסרת משתנה"
#: modules/visual_script/visual_script_editor.cpp
msgid "Editing Variable:"
-msgstr ""
+msgstr "עריכת משתנה:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove Signal"
-msgstr ""
+msgstr "הסרת ×ות"
#: modules/visual_script/visual_script_editor.cpp
msgid "Editing Signal:"
-msgstr ""
+msgstr "עריכת ×ות:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Make Tool:"
-msgstr ""
+msgstr "יצירת כלי:"
#: modules/visual_script/visual_script_editor.cpp
msgid "Members:"
-msgstr "חברי×:"
+msgstr "שדות:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Change Base Type:"
-msgstr "שינוי ערך בררת המחדל"
+msgstr "שינוי סוג הבסיס:"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Nodes..."
-msgstr "הזזת נקודה"
+msgstr "הוספת מפרקי×..."
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Function..."
-msgstr "מעבר לפונקציה…"
+msgstr "הוספת פונקציה…"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "function_name"
-msgstr "פונקציות:"
+msgstr "ש×_פונקציה"
#: modules/visual_script/visual_script_editor.cpp
msgid "Select or create a function to edit its graph."
-msgstr ""
+msgstr "יש לבחור ×ו ליצור פונקציה לעריכת ×”×ª×¨×©×™× ×©×œ×”."
#: modules/visual_script/visual_script_editor.cpp
msgid "Delete Selected"
-msgstr ""
+msgstr "מחיקת הנבחר"
#: modules/visual_script/visual_script_editor.cpp
msgid "Find Node Type"
-msgstr "×יתור סוג מפרק"
+msgstr "×יתור סוג המפרק"
#: modules/visual_script/visual_script_editor.cpp
msgid "Copy Nodes"
@@ -11980,19 +11942,16 @@ msgid "Cut Nodes"
msgstr "גזירת מפרקי×"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Make Function"
-msgstr "פונקציות:"
+msgstr "יצירת פונקציה"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Refresh Graph"
-msgstr "רענון"
+msgstr "רענון תרשי×"
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Edit Member"
-msgstr "חברי×"
+msgstr "עריכת שדה"
#: modules/visual_script/visual_script_flow_control.cpp
msgid "Input type not iterable: "
@@ -12000,11 +11959,11 @@ msgstr "סוג הקלט ×œ× ×–×ž×™×Ÿ למחזוריות: "
#: modules/visual_script/visual_script_flow_control.cpp
msgid "Iterator became invalid"
-msgstr ""
+msgstr "×יטרטור הפך ×œ×œ× ×—×•×§×™"
#: modules/visual_script/visual_script_flow_control.cpp
msgid "Iterator became invalid: "
-msgstr ""
+msgstr "×יטרטור הפך ×œ×œ× ×—×•×§×™: "
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "Invalid index property name."
@@ -12020,7 +11979,7 @@ msgstr "הנתיב ×œ× ×ž×•×‘×™×œ מפרק!"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "Invalid index property name '%s' in node %s."
-msgstr ""
+msgstr "×©× ×ž×פיין ×ינדקס ×œ× ×—×•×§×™ '%s' במפרק %s."
#: modules/visual_script/visual_script_nodes.cpp
msgid ": Invalid argument of type: "
@@ -12047,43 +12006,43 @@ msgid ""
"Invalid return value from _step(), must be integer (seq out), or string "
"(error)."
msgstr ""
+"ערך מוחזר ×œ× ×—×•×§×™ מ-_step(), חייב להיות מספר ×©×œ× (seq out) ×ו מחרוזת (שגי××”)."
#: modules/visual_script/visual_script_property_selector.cpp
-#, fuzzy
msgid "Search VisualScript"
-msgstr "חיפוש בעזרה"
+msgstr "חיפוש VisualScript"
#: modules/visual_script/visual_script_property_selector.cpp
msgid "Get %s"
-msgstr ""
+msgstr "קבלת %s"
#: modules/visual_script/visual_script_property_selector.cpp
msgid "Set %s"
-msgstr ""
+msgstr "קביעת %s"
#: platform/android/export/export.cpp
msgid "Package name is missing."
-msgstr ""
+msgstr "×©× ×”×—×‘×™×œ×” חסר."
#: platform/android/export/export.cpp
msgid "Package segments must be of non-zero length."
-msgstr ""
+msgstr "מקטעי החבילה ×—×™×™×‘×™× ×œ×”×™×•×ª ב×ורך ש×ינו ×פס."
#: platform/android/export/export.cpp
msgid "The character '%s' is not allowed in Android application package names."
-msgstr ""
+msgstr "התו '%s' ×ינו מותר בשמות חבילת ×™×™×©×•× ×נדרו×יד."
#: platform/android/export/export.cpp
msgid "A digit cannot be the first character in a package segment."
-msgstr ""
+msgstr "ספרה ××™× ×” יכולה להיות התו הר×שון במקטע חבילה."
#: platform/android/export/export.cpp
msgid "The character '%s' cannot be the first character in a package segment."
-msgstr ""
+msgstr "התו '%s' ×ינו יכול להיות התו הר×שון במקטע חבילה."
#: platform/android/export/export.cpp
msgid "The package must have at least one '.' separator."
-msgstr ""
+msgstr "החבילה חייבת לכלול לפחות מפריד '.' ×חד."
#: platform/android/export/export.cpp
msgid "Select device from the list"
@@ -12091,113 +12050,127 @@ msgstr "× × ×œ×‘×—×•×¨ התקן מהרשימה"
#: platform/android/export/export.cpp
msgid "ADB executable not configured in the Editor Settings."
-msgstr ""
+msgstr "קובץ ההפעלה של ADB ×œ× × ×§×‘×¢ בהגדרות העורך."
#: platform/android/export/export.cpp
msgid "OpenJDK jarsigner not configured in the Editor Settings."
-msgstr ""
+msgstr "OpenJDK jarsigner ×œ× × ×§×‘×¢ בהגדרות העורך."
#: platform/android/export/export.cpp
msgid "Debug keystore not configured in the Editor Settings nor in the preset."
-msgstr ""
+msgstr "מפתח לניפוי שגי×ות ×œ× × ×§×‘×¢ בהגדרות העורך ×•×œ× ×‘×”×’×“×¨×•×ª הייצו×."
#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
-msgstr ""
+msgstr "מפתח גירסת שיחרור נקבע ב×ופן שגוי בהגדרות הייצו×."
#: platform/android/export/export.cpp
msgid "Custom build requires a valid Android SDK path in Editor Settings."
msgstr ""
+"בנייה מות×מת ×ישית דורשת נתיב חוקי של ערכת פיתוח ל×נדרו×יד בהגדרות העורך."
#: platform/android/export/export.cpp
msgid "Invalid Android SDK path for custom build in Editor Settings."
msgstr ""
+"נתיב ×œ× ×—×•×§×™ לערכת פיתוח ×נדרו×יד עבור בנייה מות×מת ×ישית בהגדרות העורך."
#: platform/android/export/export.cpp
msgid ""
"Android build template not installed in the project. Install it from the "
"Project menu."
-msgstr ""
+msgstr "תבנית בנייה ל×נדרו×יד ×œ× ×ž×•×ª×§× ×ª בפרוייקט. ההתקנה ×”×™× ×ž×ª×¤×¨×™×˜ המיז×."
#: platform/android/export/export.cpp
msgid "Invalid public key for APK expansion."
-msgstr ""
+msgstr "מפתח ציבורי ×œ× ×—×•×§×™ להרחבת APK."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Invalid package name:"
-msgstr "×©× ×©×’×•×™."
+msgstr "×©× ×—×‘×™×œ×” ×œ× ×—×•×§×™:"
#: platform/android/export/export.cpp
msgid ""
"Invalid \"GodotPaymentV3\" module included in the \"android/modules\" "
"project setting (changed in Godot 3.2.2).\n"
msgstr ""
+"מודול \"GodotPaymentV3\" ×œ× ×—×•×§×™ × ×ž×¦× ×‘×”×’×“×¨×ª ×”×ž×™×–× ×‘-\"×נדרו×יד/מודולי×"
+"\" (שינוי בגודו 3.2.2).\n"
#: platform/android/export/export.cpp
msgid "\"Use Custom Build\" must be enabled to use the plugins."
-msgstr ""
+msgstr "חובה ל×פשר ״שימוש בבניה מות×מת ×ישית״ כדי להשתמש בתוספי×."
#: platform/android/export/export.cpp
+#, fuzzy
msgid ""
"\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR"
"\"."
-msgstr ""
+msgstr "\"דרגות של חופש\" תקף רק ×›×שר \"מצב Xr\" ×”×•× \"Oculus Mobile VR\"."
#: platform/android/export/export.cpp
+#, fuzzy
msgid ""
"\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
-msgstr ""
+msgstr "\"Hand Tracking\" תקף רק ×›×שר \"מצב Xr\" ×”×•× \"Oculus Mobile VR\"."
#: platform/android/export/export.cpp
+#, fuzzy
msgid ""
"\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
-msgstr ""
+msgstr "\"Focus Awareness\" תקף רק ×›×שר \"מצב Xr\" ×”×•× \"Oculus Mobile VR\"."
#: platform/android/export/export.cpp
msgid ""
"Trying to build from a custom built template, but no version info for it "
"exists. Please reinstall from the 'Project' menu."
msgstr ""
+"מנסה לבנות מתבנית מות×מת ×ישית, ×ך ×œ× ×§×™×™× ×ž×™×“×¢ על גירסת הבניה. × × ×œ×”×ª×§×™×Ÿ "
+"מחדש מתפריט 'Project'."
#: platform/android/export/export.cpp
+#, fuzzy
msgid ""
"Android build version mismatch:\n"
" Template installed: %s\n"
" Godot Version: %s\n"
"Please reinstall Android build template from 'Project' menu."
msgstr ""
+"חוסר הת×מה בגירסת ×נדרו×יד:\n"
+" תבנית הותקנה: %s\n"
+" גרסת גודו: %s\n"
+"× × ×œ×”×ª×§×™×Ÿ מחדש ×ת תבנית בניית ×נדרו×יד מתפריט 'Project'."
#: platform/android/export/export.cpp
msgid "Building Android Project (gradle)"
-msgstr ""
+msgstr "בניית ×ž×™×–× ×נדרו×יד (gradle)"
#: platform/android/export/export.cpp
msgid ""
"Building of Android project failed, check output for the error.\n"
"Alternatively visit docs.godotengine.org for Android build documentation."
msgstr ""
+"בניית ×ž×™×–× ×נדרו×יד נכשלה, ניתן לבדוק ×ת הפלט ל×יתור השגי××”.\n"
+"לחלופין, ×§×™×™× ×‘- docs.godotengine.org תיעוד לבניית ×נדרו×יד."
#: platform/android/export/export.cpp
msgid "No build apk generated at: "
-msgstr ""
+msgstr "×œ× × ×•×¦×¨ apk ב: "
#: platform/iphone/export/export.cpp
msgid "Identifier is missing."
-msgstr ""
+msgstr "מזהה חסר."
#: platform/iphone/export/export.cpp
msgid "The character '%s' is not allowed in Identifier."
-msgstr ""
+msgstr "התו '%s' ×ינו מותר במזהה."
#: platform/iphone/export/export.cpp
msgid "App Store Team ID not specified - cannot configure the project."
-msgstr ""
+msgstr "×œ× ×¦×•×™×Ÿ App Store Team ID - ×œ× × ×™×ª×Ÿ להגדיר ×ת המיז×."
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "Invalid Identifier:"
-msgstr "גודל הגופן שגוי."
+msgstr "מזהה ×œ× ×—×•×§×™:"
#: platform/iphone/export/export.cpp
msgid "Required icon is not specified in the preset."
diff --git a/editor/translations/hi.po b/editor/translations/hi.po
index 70d7a4d6b3..0fd6f92fbb 100644
--- a/editor/translations/hi.po
+++ b/editor/translations/hi.po
@@ -1136,6 +1136,16 @@ msgid "Gold Sponsors"
msgstr "गोलà¥à¤¡ पà¥à¤°à¤¾à¤¯à¥‹à¤œà¤•"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "रजत दाताओं"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "कांसà¥à¤¯ दाताओं"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "मिनी पà¥à¤°à¤¾à¤¯à¥‹à¤œà¤•"
diff --git a/editor/translations/hr.po b/editor/translations/hr.po
index a515a912b0..2779300580 100644
--- a/editor/translations/hr.po
+++ b/editor/translations/hr.po
@@ -1123,6 +1123,16 @@ msgid "Gold Sponsors"
msgstr "Zlatni sponzori"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Srebrni donatori"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "BronÄani donatori"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Mini sponzori"
diff --git a/editor/translations/hu.po b/editor/translations/hu.po
index c6828cc7d3..40a6462c90 100644
--- a/editor/translations/hu.po
+++ b/editor/translations/hu.po
@@ -1188,6 +1188,16 @@ msgid "Gold Sponsors"
msgstr "Arany Szponzorok"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Ezüst Adományozók"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Bronz Adományozók"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Mini Szponzorok"
diff --git a/editor/translations/id.po b/editor/translations/id.po
index cf4bd738fa..34c15ae95f 100644
--- a/editor/translations/id.po
+++ b/editor/translations/id.po
@@ -20,7 +20,7 @@
# Alphin Albukhari <alphinalbukhari5@gmail.com>, 2019.
# I Dewa Agung Adhinata <agungnata2003@gmail.com>, 2019.
# herri siagian <herry.it.2007@gmail.com>, 2019.
-# MonsterGila <fikrirazor@outlook.co.id>, 2019.
+# MonsterGila <fikrirazor@outlook.co.id>, 2019, 2020.
# Modeus Darksono <garuga17@gmail.com>, 2019.
# Akhmad Zulfikar <azuldegratz@gmail.com>, 2020.
# Ade Fikri Malihuddin <ade.fm97@gmail.com>, 2020.
@@ -31,8 +31,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-07-06 04:41+0000\n"
-"Last-Translator: yusuf afandi <afandi.yusuf.04@gmail.com>\n"
+"PO-Revision-Date: 2020-08-12 08:00+0000\n"
+"Last-Translator: MonsterGila <fikrirazor@outlook.co.id>\n"
"Language-Team: Indonesian <https://hosted.weblate.org/projects/godot-engine/"
"godot/id/>\n"
"Language: id\n"
@@ -1160,6 +1160,16 @@ msgid "Gold Sponsors"
msgstr "Sponsor Emas"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Donatur Perak"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Donatur Perunggu"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Sponsor Mini"
@@ -2435,10 +2445,13 @@ msgid "Reload Saved Scene"
msgstr "Simpan Skena"
#: editor/editor_node.cpp
+#, fuzzy
msgid ""
"The current scene has unsaved changes.\n"
"Reload the saved scene anyway? This action cannot be undone."
msgstr ""
+"Skena saat ini mempunyai perubahan yang belum tersimpan.\n"
+"Tetap muat ulang skena yang tersimpan? Aksi ini tidak dapat dibatalkan."
#: editor/editor_node.cpp
msgid "Quick Run Scene..."
@@ -10683,11 +10696,14 @@ msgid "Open Documentation"
msgstr "Buka Dokumentasi"
#: editor/scene_tree_dock.cpp
+#, fuzzy
msgid ""
"Cannot attach a script: there are no languages registered.\n"
"This is probably because this editor was built with all language modules "
"disabled."
msgstr ""
+"Tidak dapat melampirkan skrip: tidak ada bahasa yang terdaftar.\n"
+"Ini mungkin karena editor ini dibuat dengan semua modul bahasa dinonaktifkan."
#: editor/scene_tree_dock.cpp
msgid "Add Child Node"
@@ -12240,10 +12256,14 @@ msgstr ""
"ciptakan resource shape untuknya!"
#: scene/2d/collision_shape_2d.cpp
+#, fuzzy
msgid ""
"Polygon-based shapes are not meant be used nor edited directly through the "
"CollisionShape2D node. Please use the CollisionPolygon2D node instead."
msgstr ""
+"Bentuk Polygon-based tidak dimaksudkan untuk digunakan atau diedit secara "
+"langsung melalui node CollisionShape2D. Silakan gunakan node "
+"CollisionPolygon2D sebagai gantinya."
#: scene/2d/cpu_particles_2d.cpp
msgid ""
@@ -12429,8 +12449,9 @@ msgid "Finishing Plot"
msgstr "Menyelesaikan Pemetaan"
#: scene/3d/baked_lightmap.cpp
+#, fuzzy
msgid "Lighting Meshes: "
-msgstr ""
+msgstr "Lighting Meshes: "
#: scene/3d/collision_object.cpp
msgid ""
@@ -12485,8 +12506,9 @@ msgid ""
msgstr ""
#: scene/3d/cpu_particles.cpp
+#, fuzzy
msgid "Nothing is visible because no mesh has been assigned."
-msgstr ""
+msgstr "Tidak ada yang tampak karena tidak ada mesh yang ditetapkan."
#: scene/3d/cpu_particles.cpp
msgid ""
diff --git a/editor/translations/is.po b/editor/translations/is.po
index d53a9d609d..16958ecf41 100644
--- a/editor/translations/is.po
+++ b/editor/translations/is.po
@@ -1143,6 +1143,14 @@ msgid "Gold Sponsors"
msgstr ""
#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr ""
diff --git a/editor/translations/it.po b/editor/translations/it.po
index b2dac5ae0e..7617e0e8de 100644
--- a/editor/translations/it.po
+++ b/editor/translations/it.po
@@ -54,12 +54,13 @@
# Lorenzo Asolan <brixiumx@gmail.com>, 2020.
# Lorenzo Cerqua <lorenzocerqua@tutanota.com>, 2020.
# Federico Manzella <ferdiu.manzella@gmail.com>, 2020.
+# Ziv D <wizdavid@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-08-05 16:58+0000\n"
-"Last-Translator: Lorenzo Cerqua <lorenzocerqua@tutanota.com>\n"
+"PO-Revision-Date: 2020-09-02 14:35+0000\n"
+"Last-Translator: Ziv D <wizdavid@gmail.com>\n"
"Language-Team: Italian <https://hosted.weblate.org/projects/godot-engine/"
"godot/it/>\n"
"Language: it\n"
@@ -67,7 +68,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.2-dev\n"
+"X-Generator: Weblate 4.3-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1188,6 +1189,16 @@ msgid "Gold Sponsors"
msgstr "Sponsor oro"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Donatori argento"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Donatori bronzo"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Sponsor mini"
@@ -1758,7 +1769,7 @@ msgstr "Nuovo"
#: editor/editor_feature_profile.cpp editor/editor_node.cpp
#: editor/project_manager.cpp
msgid "Import"
-msgstr "Importa"
+msgstr "Importare"
#: editor/editor_feature_profile.cpp editor/project_export.cpp
msgid "Export"
@@ -4800,7 +4811,7 @@ msgstr "Modalità Gioco:"
#: editor/plugins/animation_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "AnimationTree"
-msgstr "AnimazioneAlbero"
+msgstr "AnimationTree"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "New name:"
@@ -12058,7 +12069,7 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
-"Debug keystore non configurato correttamente nel preset di esportazione."
+"Release keystore non configurato correttamente nel preset di esportazione."
#: platform/android/export/export.cpp
msgid "Custom build requires a valid Android SDK path in Editor Settings."
@@ -12191,9 +12202,8 @@ msgid "Run in Browser"
msgstr "Esegui nel Browser"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Run exported HTML in the system's default browser."
-msgstr "Esegui HTML esportato all'interno del browser di sistema predefinito."
+msgstr "Esegui il codice HTML esportato nel browser di sistema predefinito."
#: platform/javascript/export/export.cpp
msgid "Could not write file:"
@@ -12216,9 +12226,8 @@ msgid "Could not read boot splash image file:"
msgstr "Impossibile leggere il file immagine di avvio splash:"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Using default boot splash image."
-msgstr "Utilizzando l'immagine di splash di avvio predefinita."
+msgstr "Utilizzando l'immagine splash predefinita."
#: platform/uwp/export/export.cpp
msgid "Invalid package short name."
diff --git a/editor/translations/ja.po b/editor/translations/ja.po
index e0a1d4d909..8e82a94abf 100644
--- a/editor/translations/ja.po
+++ b/editor/translations/ja.po
@@ -36,7 +36,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-08-11 14:04+0000\n"
+"PO-Revision-Date: 2020-08-28 13:09+0000\n"
"Last-Translator: Wataru Onuki <bettawat@yahoo.co.jp>\n"
"Language-Team: Japanese <https://hosted.weblate.org/projects/godot-engine/"
"godot/ja/>\n"
@@ -45,7 +45,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.2-dev\n"
+"X-Generator: Weblate 4.2.1-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1164,6 +1164,16 @@ msgid "Gold Sponsors"
msgstr "ゴールドスãƒãƒ³ã‚µãƒ¼"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "シルãƒãƒ¼ãƒ‰ãƒŠãƒ¼"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "ブロンズドナー"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "ミニスãƒãƒ³ã‚µãƒ¼"
@@ -2751,11 +2761,11 @@ msgstr "ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«"
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Set Up Version Control"
-msgstr "ãƒãƒ¼ã‚¸ãƒ§ãƒ³ç®¡ç†ã®ã‚»ãƒƒãƒˆã‚¢ãƒƒãƒ—"
+msgstr "ãƒãƒ¼ã‚¸ãƒ§ãƒ³ç®¡ç†ã‚’セットアップ"
#: editor/editor_node.cpp
msgid "Shut Down Version Control"
-msgstr "ãƒãƒ¼ã‚¸ãƒ§ãƒ³ç®¡ç†ã®çµ‚了"
+msgstr "ãƒãƒ¼ã‚¸ãƒ§ãƒ³ç®¡ç†ã‚’終了"
#: editor/editor_node.cpp
msgid "Export..."
@@ -2894,11 +2904,11 @@ msgstr "スクリーンショットã¯Editor Data / Settingsフォルダã«ä¿å­
#: editor/editor_node.cpp
msgid "Toggle Fullscreen"
-msgstr "ãƒ•ãƒ«ã‚¹ã‚¯ãƒªãƒ¼ãƒ³ã®æœ‰åŠ¹åŒ– / 無効化"
+msgstr "フルスクリーンを有効化 / 無効化"
#: editor/editor_node.cpp
msgid "Toggle System Console"
-msgstr "ã‚·ã‚¹ãƒ†ãƒ ã‚³ãƒ³ã‚½ãƒ¼ãƒ«ã®æœ‰åŠ¹åŒ– / 無効化"
+msgstr "システムコンソールを有効化 / 無効化"
#: editor/editor_node.cpp
msgid "Open Editor Data/Settings Folder"
@@ -7011,11 +7021,11 @@ msgstr "å³ã‚¤ãƒ³ãƒ‡ãƒ³ãƒˆ"
#: editor/plugins/script_text_editor.cpp
msgid "Toggle Comment"
-msgstr "コメントã®åˆ‡ã‚Šæ›¿ãˆ"
+msgstr "コメントアウト / 解除"
#: editor/plugins/script_text_editor.cpp
msgid "Fold/Unfold Line"
-msgstr "行を折りãŸãŸã‚€ / 展開ã™ã‚‹"
+msgstr "行を折りãŸãŸã‚€ / 展開"
#: editor/plugins/script_text_editor.cpp
msgid "Fold All Lines"
@@ -7023,7 +7033,7 @@ msgstr "ã™ã¹ã¦ã®è¡Œã‚’折りãŸãŸã‚€"
#: editor/plugins/script_text_editor.cpp
msgid "Unfold All Lines"
-msgstr "ã™ã¹ã¦ã®è¡Œã‚’展開ã™ã‚‹"
+msgstr "ã™ã¹ã¦ã®è¡Œã‚’展開"
#: editor/plugins/script_text_editor.cpp
msgid "Clone Down"
@@ -7035,7 +7045,7 @@ msgstr "シンボルを補完"
#: editor/plugins/script_text_editor.cpp
msgid "Evaluate Selection"
-msgstr "é¸æŠžç¯„å›²ã‚’è©•ä¾¡ã™ã‚‹"
+msgstr "é¸æŠžç¯„å›²ã‚’è©•ä¾¡"
#: editor/plugins/script_text_editor.cpp
msgid "Trim Trailing Whitespace"
diff --git a/editor/translations/ka.po b/editor/translations/ka.po
index 1bfd23080b..75fbad354b 100644
--- a/editor/translations/ka.po
+++ b/editor/translations/ka.po
@@ -1185,6 +1185,16 @@ msgid "Gold Sponsors"
msgstr "áƒáƒ¥áƒ áƒáƒ¡ სპáƒáƒœáƒ¡áƒáƒ áƒ”ბი"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "ვერცხლის დáƒáƒœáƒáƒ¢áƒáƒ áƒ”ბი"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "ბრინჯáƒáƒáƒ¡ დáƒáƒœáƒáƒ¢áƒáƒ áƒ”ბი"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "მინი სპáƒáƒœáƒ¡áƒáƒ áƒ”ბი"
diff --git a/editor/translations/ko.po b/editor/translations/ko.po
index 9b19450d58..f9fa96982f 100644
--- a/editor/translations/ko.po
+++ b/editor/translations/ko.po
@@ -1150,6 +1150,16 @@ msgid "Gold Sponsors"
msgstr "골드 스í°ì„œ"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "실버 기부ìž"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "브론즈 기부ìž"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "미니 스í°ì„œ"
diff --git a/editor/translations/lt.po b/editor/translations/lt.po
index 4d3884d5f8..6449d264ad 100644
--- a/editor/translations/lt.po
+++ b/editor/translations/lt.po
@@ -1148,6 +1148,14 @@ msgid "Gold Sponsors"
msgstr ""
#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr ""
diff --git a/editor/translations/lv.po b/editor/translations/lv.po
index 2612b441c6..6cf590f8c5 100644
--- a/editor/translations/lv.po
+++ b/editor/translations/lv.po
@@ -1140,6 +1140,16 @@ msgid "Gold Sponsors"
msgstr "Zelta Sponsori"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Sudraba Donors"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Bronzas Donors"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Mini Sponsori"
diff --git a/editor/translations/mi.po b/editor/translations/mi.po
index 07a3bdae3c..30ac5ce885 100644
--- a/editor/translations/mi.po
+++ b/editor/translations/mi.po
@@ -1099,6 +1099,14 @@ msgid "Gold Sponsors"
msgstr ""
#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr ""
diff --git a/editor/translations/ml.po b/editor/translations/ml.po
index aa7844d7ab..70be9f00c8 100644
--- a/editor/translations/ml.po
+++ b/editor/translations/ml.po
@@ -1109,6 +1109,14 @@ msgid "Gold Sponsors"
msgstr ""
#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr ""
diff --git a/editor/translations/mr.po b/editor/translations/mr.po
index 043d7e643e..a9719278c0 100644
--- a/editor/translations/mr.po
+++ b/editor/translations/mr.po
@@ -1106,6 +1106,14 @@ msgid "Gold Sponsors"
msgstr ""
#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr ""
diff --git a/editor/translations/ms.po b/editor/translations/ms.po
index ad70f291ca..940feeb863 100644
--- a/editor/translations/ms.po
+++ b/editor/translations/ms.po
@@ -7,13 +7,14 @@
# Syaz Amirin <amirin123z@gmail.com>, 2018.
# Nafis Ibrahim <thepreciousnafis@gmail.com>, 2018.
# Muhammad Hazim bin Hafizalshah <muhammadhazimhafizalshah@gmail.com>, 2020.
+# keviinx <keviinx@yahoo.com>, 2020.
+# Keviindran Ramachandran <keviinx@yahoo.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-01-27 07:10+0000\n"
-"Last-Translator: Muhammad Hazim bin Hafizalshah "
-"<muhammadhazimhafizalshah@gmail.com>\n"
+"PO-Revision-Date: 2020-09-02 14:35+0000\n"
+"Last-Translator: Keviindran Ramachandran <keviinx@yahoo.com>\n"
"Language-Team: Malay <https://hosted.weblate.org/projects/godot-engine/godot/"
"ms/>\n"
"Language: ms\n"
@@ -21,119 +22,118 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 3.11-dev\n"
+"X-Generator: Weblate 4.3-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Invalid type argument to convert(), use TYPE_* constants."
-msgstr ""
+msgstr "Argumen jenis tidak sah untuk convert(), guna pemalar TYPE_*."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
-msgstr ""
+msgstr "Menjangkakan rentetan dengan panjang 1 (satu watak)."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Not enough bytes for decoding bytes, or invalid format."
-msgstr ""
+msgstr "Bait tidak mencukupi untuk menyahkod bait, atau format tidak sah."
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
-msgstr ""
+msgstr "Input %i tidak sah (tidak lulus) dalam ungkapan"
#: core/math/expression.cpp
msgid "self can't be used because instance is null (not passed)"
-msgstr ""
+msgstr "self tidak boleh digunakan kerana instance adalah null (tidak lulus)"
#: core/math/expression.cpp
msgid "Invalid operands to operator %s, %s and %s."
-msgstr ""
+msgstr "Operan tidak sah untuk pengendali %s, %s dan %s."
#: core/math/expression.cpp
msgid "Invalid index of type %s for base type %s"
-msgstr ""
+msgstr "Indeks tidak sah untuk jenis %s untuk jenis asa %s"
#: core/math/expression.cpp
msgid "Invalid named index '%s' for base type %s"
-msgstr ""
+msgstr "Indeks bernama tidak sah '%s' untuk jenis asa %s"
#: core/math/expression.cpp
msgid "Invalid arguments to construct '%s'"
-msgstr ""
+msgstr "Argumen tidak sah untuk binaan '%s'"
#: core/math/expression.cpp
msgid "On call to '%s':"
-msgstr ""
+msgstr "Atas panggilan ke '%s':"
#: core/ustring.cpp
msgid "B"
-msgstr ""
+msgstr "B"
#: core/ustring.cpp
msgid "KiB"
-msgstr ""
+msgstr "KiB"
#: core/ustring.cpp
msgid "MiB"
-msgstr ""
+msgstr "MiB"
#: core/ustring.cpp
msgid "GiB"
-msgstr ""
+msgstr "GiB"
#: core/ustring.cpp
msgid "TiB"
-msgstr ""
+msgstr "TiB"
#: core/ustring.cpp
msgid "PiB"
-msgstr ""
+msgstr "PiB"
#: core/ustring.cpp
msgid "EiB"
-msgstr ""
+msgstr "EiB"
#: editor/animation_bezier_editor.cpp
msgid "Free"
-msgstr ""
+msgstr "Bebas"
#: editor/animation_bezier_editor.cpp
msgid "Balanced"
-msgstr ""
+msgstr "Seimbang"
#: editor/animation_bezier_editor.cpp
msgid "Mirror"
-msgstr ""
+msgstr "Cermin"
#: editor/animation_bezier_editor.cpp editor/editor_profiler.cpp
msgid "Time:"
-msgstr ""
+msgstr "Masa:"
#: editor/animation_bezier_editor.cpp
msgid "Value:"
-msgstr ""
+msgstr "Nilai:"
#: editor/animation_bezier_editor.cpp
msgid "Insert Key Here"
-msgstr ""
+msgstr "Masukkan Kunci di Sini"
#: editor/animation_bezier_editor.cpp
-#, fuzzy
msgid "Duplicate Selected Key(s)"
-msgstr "Anim Menduakan Kunci"
+msgstr "Gandakan Kunci Terpilih"
#: editor/animation_bezier_editor.cpp
msgid "Delete Selected Key(s)"
-msgstr ""
+msgstr "Padam Kunci Terpilih"
#: editor/animation_bezier_editor.cpp
msgid "Add Bezier Point"
-msgstr ""
+msgstr "Tambah Titik Bezier"
#: editor/animation_bezier_editor.cpp
msgid "Move Bezier Points"
-msgstr ""
+msgstr "Pindah Titik-titik Bezier"
#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
msgid "Anim Duplicate Keys"
@@ -141,10 +141,9 @@ msgstr "Anim Menduakan Kunci"
#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp
msgid "Anim Delete Keys"
-msgstr ""
+msgstr "Anim Padam Kunci"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Change Keyframe Time"
msgstr "Anim Ubah Masa Keyframe"
@@ -154,7 +153,7 @@ msgstr "Anim Ubah Peralihan"
#: editor/animation_track_editor.cpp
msgid "Anim Change Transform"
-msgstr "Anim Ubah Penukaran"
+msgstr "Anim Ubah Perubahan"
#: editor/animation_track_editor.cpp
msgid "Anim Change Keyframe Value"
@@ -165,200 +164,192 @@ msgid "Anim Change Call"
msgstr "Anim Ubah Panggilan"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Keyframe Time"
-msgstr "Anim Ubah Masa Keyframe"
+msgstr "Anim Ubah Pelbagai Masa Keyframe"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Transition"
-msgstr "Anim Ubah Peralihan"
+msgstr "Anim Ubah Pelbagai Peralihan"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Transform"
-msgstr "Anim Ubah Penukaran"
+msgstr "Anim Ubah Pelbagai Penukaran"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Keyframe Value"
-msgstr "Anim Ubah Nilai Keyframe"
+msgstr "Anim Ubah Pelbagai Nilai Keyframe"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Anim Multi Change Call"
-msgstr "Anim Ubah Panggilan"
+msgstr "Anim Ubah Pelbagai Panggilan"
#: editor/animation_track_editor.cpp
msgid "Change Animation Length"
-msgstr ""
+msgstr "Ubah Panjang Animasi"
#: editor/animation_track_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Change Animation Loop"
-msgstr ""
+msgstr "Ubah Gelung Animasi"
#: editor/animation_track_editor.cpp
msgid "Property Track"
-msgstr ""
+msgstr "Trek Sifat"
#: editor/animation_track_editor.cpp
msgid "3D Transform Track"
-msgstr ""
+msgstr "Trek Transformasi 3D"
#: editor/animation_track_editor.cpp
msgid "Call Method Track"
-msgstr ""
+msgstr "Trek Panggilan Kaedah"
#: editor/animation_track_editor.cpp
msgid "Bezier Curve Track"
-msgstr ""
+msgstr "Trek Lengkung Bezier"
#: editor/animation_track_editor.cpp
msgid "Audio Playback Track"
-msgstr ""
+msgstr "Trek Main balik Audio"
#: editor/animation_track_editor.cpp
msgid "Animation Playback Track"
-msgstr ""
+msgstr "Trek Main Balik Animasi"
#: editor/animation_track_editor.cpp
msgid "Animation length (frames)"
-msgstr ""
+msgstr "Panjang animasi (bingkai)"
#: editor/animation_track_editor.cpp
msgid "Animation length (seconds)"
-msgstr ""
+msgstr "Panjang animasi (saat)"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Add Track"
-msgstr "Anim Tambah Trek"
+msgstr "Tambah Trek"
#: editor/animation_track_editor.cpp
msgid "Animation Looping"
-msgstr ""
+msgstr "Gelung Animasi"
#: editor/animation_track_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Functions:"
-msgstr ""
+msgstr "Fungsi:"
#: editor/animation_track_editor.cpp
msgid "Audio Clips:"
-msgstr ""
+msgstr "Klip Audio:"
#: editor/animation_track_editor.cpp
msgid "Anim Clips:"
-msgstr ""
+msgstr "Klip Anim:"
#: editor/animation_track_editor.cpp
msgid "Change Track Path"
-msgstr ""
+msgstr "Tukar Laluan Trek"
#: editor/animation_track_editor.cpp
msgid "Toggle this track on/off."
-msgstr ""
+msgstr "Hidupkan / matikan trek ini."
#: editor/animation_track_editor.cpp
msgid "Update Mode (How this property is set)"
-msgstr ""
+msgstr "Kemas kini Mod (Bagaimana sifat ini ditetapkan)"
#: editor/animation_track_editor.cpp
msgid "Interpolation Mode"
-msgstr ""
+msgstr "Mod Interpolasi"
#: editor/animation_track_editor.cpp
msgid "Loop Wrap Mode (Interpolate end with beginning on loop)"
-msgstr ""
+msgstr "Mod Gelung Balut (Interpolat hujung dengan permulaan pada gelung)"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Remove this track."
-msgstr "Buang Trek Anim"
+msgstr "Keluarkan trek ini."
#: editor/animation_track_editor.cpp
msgid "Time (s): "
-msgstr ""
+msgstr "Masa (s): "
#: editor/animation_track_editor.cpp
msgid "Toggle Track Enabled"
-msgstr ""
+msgstr "Togol Trek Diaktifkan"
#: editor/animation_track_editor.cpp
msgid "Continuous"
-msgstr ""
+msgstr "Berterusan"
#: editor/animation_track_editor.cpp
msgid "Discrete"
-msgstr ""
+msgstr "Diskret"
#: editor/animation_track_editor.cpp
msgid "Trigger"
-msgstr ""
+msgstr "Pencetus"
#: editor/animation_track_editor.cpp
msgid "Capture"
-msgstr ""
+msgstr "Tangkap"
#: editor/animation_track_editor.cpp
msgid "Nearest"
-msgstr ""
+msgstr "Terdekat"
#: editor/animation_track_editor.cpp editor/plugins/curve_editor_plugin.cpp
#: editor/property_editor.cpp
msgid "Linear"
-msgstr ""
+msgstr "Linear"
#: editor/animation_track_editor.cpp
msgid "Cubic"
-msgstr ""
+msgstr "Kubik"
#: editor/animation_track_editor.cpp
msgid "Clamp Loop Interp"
-msgstr ""
+msgstr "Kepit Gelung Interp"
#: editor/animation_track_editor.cpp
msgid "Wrap Loop Interp"
-msgstr ""
+msgstr "Balut Gelung Interp"
#: editor/animation_track_editor.cpp
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Insert Key"
-msgstr ""
+msgstr "Masukkan Kunci"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Duplicate Key(s)"
-msgstr "Anim Menduakan Kunci"
+msgstr "Menduakan Kunci"
#: editor/animation_track_editor.cpp
msgid "Delete Key(s)"
-msgstr ""
+msgstr "Padam Kunci"
#: editor/animation_track_editor.cpp
msgid "Change Animation Update Mode"
-msgstr ""
+msgstr "Mod Tukar Kemas Kini Animasi"
#: editor/animation_track_editor.cpp
msgid "Change Animation Interpolation Mode"
-msgstr ""
+msgstr "Tukar Mod Interpolasi Animasi"
#: editor/animation_track_editor.cpp
msgid "Change Animation Loop Mode"
-msgstr ""
+msgstr "Tukar Mod Gelung Animasi"
#: editor/animation_track_editor.cpp
msgid "Remove Anim Track"
-msgstr "Buang Trek Anim"
+msgstr "Keluarkan Trek Anim"
#: editor/animation_track_editor.cpp
msgid "Create NEW track for %s and insert key?"
-msgstr ""
+msgstr "Cipta trek BARU untuk %s dan masukkan kunci?"
#: editor/animation_track_editor.cpp
msgid "Create %d NEW tracks and insert keys?"
-msgstr ""
+msgstr "Cipta %d BARU trek dan masukkan kunci?"
#: editor/animation_track_editor.cpp editor/create_dialog.cpp
#: editor/editor_audio_buses.cpp editor/editor_feature_profile.cpp
@@ -370,40 +361,39 @@ msgstr ""
#: editor/script_create_dialog.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Create"
-msgstr ""
+msgstr "Cipta"
#: editor/animation_track_editor.cpp
msgid "Anim Insert"
-msgstr ""
+msgstr "Masukkan Anim"
#: editor/animation_track_editor.cpp
msgid "AnimationPlayer can't animate itself, only other players."
-msgstr ""
+msgstr "AnimationPlayer tidak animasikan dirinya sendiri, hanya pemain lain."
#: editor/animation_track_editor.cpp
msgid "Anim Create & Insert"
-msgstr ""
+msgstr "Anim Cipta & Masukkan"
#: editor/animation_track_editor.cpp
msgid "Anim Insert Track & Key"
-msgstr ""
+msgstr "Anim Masukkan Trek & Kunci"
#: editor/animation_track_editor.cpp
msgid "Anim Insert Key"
-msgstr ""
+msgstr "Anim Masukkan Kunci"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Change Animation Step"
-msgstr "Anim Ubah Peralihan"
+msgstr "Tukar Langkah Animasi"
#: editor/animation_track_editor.cpp
msgid "Rearrange Tracks"
-msgstr ""
+msgstr "Susun semula Trek"
#: editor/animation_track_editor.cpp
msgid "Transform tracks only apply to Spatial-based nodes."
-msgstr ""
+msgstr "Transformasi trek hanya berlaku kepada nod berasaskan Spatial."
#: editor/animation_track_editor.cpp
msgid ""
@@ -412,78 +402,82 @@ msgid ""
"-AudioStreamPlayer2D\n"
"-AudioStreamPlayer3D"
msgstr ""
+"Trek audio hanya boleh ditujukan kepada nod jenis:\n"
+"-AudioStreamPlayer\n"
+"-AudioStreamPlayer2D\n"
+"-AudioStreamPlayer3D"
#: editor/animation_track_editor.cpp
msgid "Animation tracks can only point to AnimationPlayer nodes."
-msgstr ""
+msgstr "Trek animasi hanya dapat ditujukan kepada nod AnimationPlayer."
#: editor/animation_track_editor.cpp
msgid "An animation player can't animate itself, only other players."
msgstr ""
+"Pemain animasi tidak boleh animasikan dirinya sendiri, hanya pemain lain."
#: editor/animation_track_editor.cpp
msgid "Not possible to add a new track without a root"
-msgstr ""
+msgstr "Tidak boleh menambah trek baru tanpa satu akar"
#: editor/animation_track_editor.cpp
msgid "Invalid track for Bezier (no suitable sub-properties)"
-msgstr ""
+msgstr "Trek tidak sah untuk Bezier (tiada sub-sifat yang sesuai)"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Add Bezier Track"
-msgstr "Anim Tambah Trek"
+msgstr "Tambah Trek Bezier"
#: editor/animation_track_editor.cpp
msgid "Track path is invalid, so can't add a key."
-msgstr ""
+msgstr "Laluan trek tidak sah, maka tidak boleh menambahkan kunci."
#: editor/animation_track_editor.cpp
msgid "Track is not of type Spatial, can't insert key"
-msgstr ""
+msgstr "Trek bukan jenis Spatial, tidak boleh memasukkan kunci"
#: editor/animation_track_editor.cpp
msgid "Add Transform Track Key"
-msgstr ""
+msgstr "Tambah Kunci Trek Transformasi"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Add Track Key"
-msgstr "Anim Tambah Trek"
+msgstr "Tambah Kunci Trek"
#: editor/animation_track_editor.cpp
msgid "Track path is invalid, so can't add a method key."
-msgstr ""
+msgstr "Laluan trek tidak sah, maka tidak boleh menambahkan kunci kaedah."
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Add Method Track Key"
-msgstr "Anim Tambah Trek"
+msgstr "Tambah Kunci Trek Kaedah"
#: editor/animation_track_editor.cpp
msgid "Method not found in object: "
-msgstr ""
+msgstr "Kaedah tidak ditemui dalam objek: "
#: editor/animation_track_editor.cpp
msgid "Anim Move Keys"
-msgstr ""
+msgstr "Kunci Gerak Anim"
#: editor/animation_track_editor.cpp
msgid "Clipboard is empty"
-msgstr ""
+msgstr "Papan klip kosong"
#: editor/animation_track_editor.cpp
msgid "Paste Tracks"
-msgstr ""
+msgstr "Tampal Trek"
#: editor/animation_track_editor.cpp
msgid "Anim Scale Keys"
-msgstr ""
+msgstr "Kunci Skala Anim"
#: editor/animation_track_editor.cpp
msgid ""
"This option does not work for Bezier editing, as it's only a single track."
msgstr ""
+"Pilihan ini tidak berfungsi untuk pengeditan Bezier, kerana ia hanya satu "
+"trek."
#: editor/animation_track_editor.cpp
msgid ""
@@ -497,38 +491,47 @@ msgid ""
"Alternatively, use an import preset that imports animations to separate "
"files."
msgstr ""
+"Animasi ini tergolong dalam adegan yang diimport, maka perubahan untuk trek "
+"yang diimport tidak akan disimpan.\n"
+"\n"
+"Untuk memberikan keupayaan untuk menambah trek tersuai, navigasi ke tetapan "
+"import adegan dan tetapkan\n"
+"\"Animasi > Simpanan\" ke \"Fail\", aktifkan \"Animasi > Simpan Trek Tersuai"
+"\", kemudian import semula.\n"
+"Sebagai alternatif, gunakan pratetap import yang mengimportkan animasi untuk "
+"memisahkan fail."
#: editor/animation_track_editor.cpp
msgid "Warning: Editing imported animation"
-msgstr ""
+msgstr "Amaran: Mengedit animasi yang diimport"
#: editor/animation_track_editor.cpp
msgid "Select an AnimationPlayer node to create and edit animations."
-msgstr ""
+msgstr "Pilih nod AnimationPlayer untuk mencipta dan mengedit animasi."
#: editor/animation_track_editor.cpp
msgid "Only show tracks from nodes selected in tree."
-msgstr ""
+msgstr "Hanya tunjukkan trek dari nod yang dipilih di pokok."
#: editor/animation_track_editor.cpp
msgid "Group tracks by node or display them as plain list."
-msgstr ""
+msgstr "Kumpulkan trek mengikut nod atau memaparkannya sebagai senarai biasa."
#: editor/animation_track_editor.cpp
msgid "Snap:"
-msgstr ""
+msgstr "Tangkap:"
#: editor/animation_track_editor.cpp
msgid "Animation step value."
-msgstr ""
+msgstr "Nilai langkah animasi."
#: editor/animation_track_editor.cpp
msgid "Seconds"
-msgstr ""
+msgstr "Saat"
#: editor/animation_track_editor.cpp
msgid "FPS"
-msgstr ""
+msgstr "FPS"
#: editor/animation_track_editor.cpp editor/editor_properties.cpp
#: editor/plugins/polygon_2d_editor_plugin.cpp
@@ -538,108 +541,107 @@ msgstr ""
#: editor/project_settings_editor.cpp editor/property_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Edit"
-msgstr ""
+msgstr "Edit"
#: editor/animation_track_editor.cpp
msgid "Animation properties."
-msgstr ""
+msgstr "Sifat animasi."
#: editor/animation_track_editor.cpp
msgid "Copy Tracks"
-msgstr ""
+msgstr "Salin Trek"
#: editor/animation_track_editor.cpp
msgid "Scale Selection"
-msgstr ""
+msgstr "Pemilihan Skala"
#: editor/animation_track_editor.cpp
msgid "Scale From Cursor"
-msgstr ""
+msgstr "Skala Dari Kursor"
#: editor/animation_track_editor.cpp modules/gridmap/grid_map_editor_plugin.cpp
msgid "Duplicate Selection"
-msgstr ""
+msgstr "Menduakan Pilihan"
#: editor/animation_track_editor.cpp
msgid "Duplicate Transposed"
-msgstr ""
+msgstr "Menduakan Pindahan"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Delete Selection"
-msgstr "Semua Pilihan"
+msgstr "Padam Pilihan"
#: editor/animation_track_editor.cpp
msgid "Go to Next Step"
-msgstr ""
+msgstr "Pergi ke Langkah Seterusnya"
#: editor/animation_track_editor.cpp
msgid "Go to Previous Step"
-msgstr ""
+msgstr "Pergi ke Langkah Sebelumnya"
#: editor/animation_track_editor.cpp
msgid "Optimize Animation"
-msgstr ""
+msgstr "Optimumkan Animasi"
#: editor/animation_track_editor.cpp
msgid "Clean-Up Animation"
-msgstr ""
+msgstr "Bersihkan Animasi"
#: editor/animation_track_editor.cpp
msgid "Pick the node that will be animated:"
-msgstr ""
+msgstr "Pilih nod yang akan dianimasikan:"
#: editor/animation_track_editor.cpp
msgid "Use Bezier Curves"
-msgstr ""
+msgstr "Guna Lengkung Bezier"
#: editor/animation_track_editor.cpp
msgid "Anim. Optimizer"
-msgstr ""
+msgstr "Pengoptimum Anim."
#: editor/animation_track_editor.cpp
msgid "Max. Linear Error:"
-msgstr ""
+msgstr "Max. Ralat Linear:"
#: editor/animation_track_editor.cpp
msgid "Max. Angular Error:"
-msgstr ""
+msgstr "Max. Ralat Sudut:"
#: editor/animation_track_editor.cpp
msgid "Max Optimizable Angle:"
-msgstr ""
+msgstr "Sudut Maksimum yang Boleh Dioptimumkan:"
#: editor/animation_track_editor.cpp
msgid "Optimize"
-msgstr ""
+msgstr "Mengoptimumkan"
#: editor/animation_track_editor.cpp
msgid "Remove invalid keys"
-msgstr ""
+msgstr "Keluarkan kunci yang tidak sah"
#: editor/animation_track_editor.cpp
msgid "Remove unresolved and empty tracks"
-msgstr ""
+msgstr "Keluarkan trek yang tidak boleh diselesaikan dan kosong"
#: editor/animation_track_editor.cpp
msgid "Clean-up all animations"
-msgstr ""
+msgstr "Bersihkan semua animasi"
#: editor/animation_track_editor.cpp
msgid "Clean-Up Animation(s) (NO UNDO!)"
-msgstr ""
+msgstr "Bersihkan Animasi (TIDAK BOLEH BUAT ASAL!)"
#: editor/animation_track_editor.cpp
msgid "Clean-Up"
-msgstr ""
+msgstr "Bersihkan"
#: editor/animation_track_editor.cpp
msgid "Scale Ratio:"
-msgstr ""
+msgstr "Nisbah Skala:"
#: editor/animation_track_editor.cpp
msgid "Select Tracks to Copy"
-msgstr ""
+msgstr "Pilih Trek untuk Disalin"
#: editor/animation_track_editor.cpp editor/editor_log.cpp
#: editor/editor_properties.cpp
@@ -648,146 +650,146 @@ msgstr ""
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Copy"
-msgstr ""
+msgstr "Salin"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Select All/None"
-msgstr "Semua Pilihan"
+msgstr "Pilih Semua/Tiada"
#: editor/animation_track_editor_plugins.cpp
-#, fuzzy
msgid "Add Audio Track Clip"
-msgstr "Anim Tambah Trek"
+msgstr "Tambah Klip Trek Audio"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip Start Offset"
-msgstr ""
+msgstr "Tukar Klip Trek Audio Mula Offset"
#: editor/animation_track_editor_plugins.cpp
msgid "Change Audio Track Clip End Offset"
-msgstr ""
+msgstr "Tukar Klip Audio Trek Hujung Offset"
#: editor/array_property_edit.cpp
msgid "Resize Array"
-msgstr ""
+msgstr "Ubah saiz Array"
#: editor/array_property_edit.cpp
msgid "Change Array Value Type"
-msgstr ""
+msgstr "Tukar Jenis Nilai Array"
#: editor/array_property_edit.cpp
msgid "Change Array Value"
-msgstr ""
+msgstr "Tukar Nilai Array"
#: editor/code_editor.cpp
msgid "Go to Line"
-msgstr ""
+msgstr "Pergi ke Baris"
#: editor/code_editor.cpp
msgid "Line Number:"
-msgstr ""
+msgstr "Nombor Baris:"
#: editor/code_editor.cpp
msgid "%d replaced."
-msgstr ""
+msgstr "%d telah diganti."
#: editor/code_editor.cpp editor/editor_help.cpp
msgid "%d match."
-msgstr ""
+msgstr "%d padan."
#: editor/code_editor.cpp editor/editor_help.cpp
msgid "%d matches."
-msgstr ""
+msgstr "%d padan."
#: editor/code_editor.cpp editor/find_in_files.cpp
msgid "Match Case"
-msgstr ""
+msgstr "Kes Padan"
#: editor/code_editor.cpp editor/find_in_files.cpp
msgid "Whole Words"
-msgstr ""
+msgstr "Seluruh Perkataan"
#: editor/code_editor.cpp editor/rename_dialog.cpp
msgid "Replace"
-msgstr ""
+msgstr "Ganti"
#: editor/code_editor.cpp
msgid "Replace All"
-msgstr ""
+msgstr "Ganti Semua"
#: editor/code_editor.cpp
msgid "Selection Only"
-msgstr ""
+msgstr "Pilihan Sahaja"
#: editor/code_editor.cpp editor/plugins/script_text_editor.cpp
#: editor/plugins/text_editor.cpp
msgid "Standard"
-msgstr ""
+msgstr "Piawai"
#: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp
msgid "Toggle Scripts Panel"
-msgstr ""
+msgstr "Togol Panel Skrip"
#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
msgid "Zoom In"
-msgstr ""
+msgstr "Zum Masuk"
#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
msgid "Zoom Out"
-msgstr ""
+msgstr "Zum Keluar"
#: editor/code_editor.cpp
msgid "Reset Zoom"
-msgstr ""
+msgstr "Set Semula Zum"
#: editor/code_editor.cpp
msgid "Warnings"
-msgstr ""
+msgstr "Amaran"
#: editor/code_editor.cpp
msgid "Line and column numbers."
-msgstr ""
+msgstr "Nombor baris dan lajur."
#: editor/connections_dialog.cpp
msgid "Method in target node must be specified."
-msgstr ""
+msgstr "Kaedah dalam nod sasaran mesti ditentukan."
#: editor/connections_dialog.cpp
msgid "Method name must be a valid identifier."
-msgstr ""
+msgstr "Nama kaedah mestilah pengecam yang sah."
#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
msgstr ""
+"Kaedah sasaran tidak dijumpai. Tentukan kaedah yang sah atau lampirkan skrip "
+"ke nod sasaran."
#: editor/connections_dialog.cpp
msgid "Connect to Node:"
-msgstr ""
+msgstr "Sambung ke Nod:"
#: editor/connections_dialog.cpp
msgid "Connect to Script:"
-msgstr ""
+msgstr "Sambung ke Skrip:"
#: editor/connections_dialog.cpp
msgid "From Signal:"
-msgstr ""
+msgstr "Dari Isyarat:"
#: editor/connections_dialog.cpp
msgid "Scene does not contain any script."
-msgstr ""
+msgstr "Adegan tidak mengandungi sebarang skrip."
#: editor/connections_dialog.cpp editor/editor_autoload_settings.cpp
#: editor/groups_editor.cpp editor/plugins/item_list_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp editor/project_settings_editor.cpp
msgid "Add"
-msgstr ""
+msgstr "Tambah"
#: editor/connections_dialog.cpp editor/dependency_editor.cpp
#: editor/editor_feature_profile.cpp editor/groups_editor.cpp
@@ -798,44 +800,46 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp
#: editor/project_settings_editor.cpp
msgid "Remove"
-msgstr ""
+msgstr "Keluarkan"
#: editor/connections_dialog.cpp
msgid "Add Extra Call Argument:"
-msgstr ""
+msgstr "Tambah Hujah Panggilan Tambahan:"
#: editor/connections_dialog.cpp
msgid "Extra Call Arguments:"
-msgstr ""
+msgstr "Hujah Panggilan Tambahan:"
#: editor/connections_dialog.cpp
msgid "Receiver Method:"
-msgstr ""
+msgstr "Kaedah Penerima:"
#: editor/connections_dialog.cpp
msgid "Advanced"
-msgstr ""
+msgstr "Lanjutan"
#: editor/connections_dialog.cpp
msgid "Deferred"
-msgstr ""
+msgstr "Ditangguhkan"
#: editor/connections_dialog.cpp
msgid ""
"Defers the signal, storing it in a queue and only firing it at idle time."
msgstr ""
+"Mencegah isyarat, menyimpannya dalam barisan dan hanya menyalakannya pada "
+"waktu terbiar."
#: editor/connections_dialog.cpp
msgid "Oneshot"
-msgstr ""
+msgstr "Oneshot"
#: editor/connections_dialog.cpp
msgid "Disconnects the signal after its first emission."
-msgstr ""
+msgstr "Putuskan isyarat selepas pelepasan pertama."
#: editor/connections_dialog.cpp
msgid "Cannot connect signal"
-msgstr ""
+msgstr "Tidak dapat menyambungkan isyarat"
#: editor/connections_dialog.cpp editor/dependency_editor.cpp
#: editor/export_template_manager.cpp editor/groups_editor.cpp
@@ -849,101 +853,104 @@ msgstr ""
#: editor/run_settings_dialog.cpp editor/settings_config_dialog.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Close"
-msgstr ""
+msgstr "Tutup"
#: editor/connections_dialog.cpp
msgid "Connect"
-msgstr ""
+msgstr "Sambung"
#: editor/connections_dialog.cpp
msgid "Signal:"
-msgstr ""
+msgstr "Isyarat:"
#: editor/connections_dialog.cpp
msgid "Connect '%s' to '%s'"
-msgstr ""
+msgstr "Sambungkan '% s' ke '% s'"
#: editor/connections_dialog.cpp
msgid "Disconnect '%s' from '%s'"
-msgstr ""
+msgstr "Putuskan sambungan '% s' dari '% s'"
#: editor/connections_dialog.cpp
msgid "Disconnect all from signal: '%s'"
-msgstr ""
+msgstr "Putuskan semua sambungan dari isyarat: '% s'"
#: editor/connections_dialog.cpp
msgid "Connect..."
-msgstr ""
+msgstr "Sambung ..."
#: editor/connections_dialog.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Disconnect"
-msgstr ""
+msgstr "Putuskan sambungan"
#: editor/connections_dialog.cpp
msgid "Connect a Signal to a Method"
-msgstr ""
+msgstr "Sambungkan Isyarat ke Kaedah"
#: editor/connections_dialog.cpp
msgid "Edit Connection:"
-msgstr ""
+msgstr "Edit Sambungan:"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from the \"%s\" signal?"
msgstr ""
+"Adakah anda pasti anda mahu mengeluarkan semua sambungan dari isyarat \"% s"
+"\"?"
#: editor/connections_dialog.cpp editor/editor_help.cpp editor/node_dock.cpp
msgid "Signals"
-msgstr ""
+msgstr "Isyarat"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from this signal?"
msgstr ""
+"Adakah anda pasti anda mahu mengeluarkan semua sambungan dari isyarat ini?"
#: editor/connections_dialog.cpp
msgid "Disconnect All"
-msgstr ""
+msgstr "Putuskan Semua"
#: editor/connections_dialog.cpp
msgid "Edit..."
-msgstr ""
+msgstr "Edit..."
#: editor/connections_dialog.cpp
msgid "Go To Method"
-msgstr ""
+msgstr "Pergi ke Kaedah"
#: editor/create_dialog.cpp
msgid "Change %s Type"
-msgstr ""
+msgstr "Ubah Jenis %s"
#: editor/create_dialog.cpp editor/project_settings_editor.cpp
msgid "Change"
-msgstr ""
+msgstr "Ubah"
#: editor/create_dialog.cpp
msgid "Create New %s"
-msgstr ""
+msgstr "Cipta %s Baru"
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp
msgid "Favorites:"
-msgstr ""
+msgstr "Kegemaran:"
#: editor/create_dialog.cpp editor/editor_file_dialog.cpp
msgid "Recent:"
-msgstr ""
+msgstr "Terkini:"
#: editor/create_dialog.cpp editor/plugins/script_editor_plugin.cpp
#: editor/property_selector.cpp editor/quick_open.cpp
#: modules/visual_script/visual_script_property_selector.cpp
msgid "Search:"
-msgstr ""
+msgstr "Cari:"
#: editor/create_dialog.cpp editor/plugins/script_editor_plugin.cpp
#: editor/property_selector.cpp editor/quick_open.cpp
#: modules/visual_script/visual_script_property_selector.cpp
msgid "Matches:"
-msgstr ""
+msgstr "Padanan:"
#: editor/create_dialog.cpp editor/editor_plugin_settings.cpp
#: editor/plugin_config_dialog.cpp
@@ -951,57 +958,61 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp editor/property_selector.cpp
#: modules/visual_script/visual_script_property_selector.cpp
msgid "Description:"
-msgstr ""
+msgstr "Keterangan:"
#: editor/dependency_editor.cpp
msgid "Search Replacement For:"
-msgstr ""
+msgstr "Cari Penggantian Untuk:"
#: editor/dependency_editor.cpp
msgid "Dependencies For:"
-msgstr ""
+msgstr "Kebergantungan Untuk:"
#: editor/dependency_editor.cpp
msgid ""
"Scene '%s' is currently being edited.\n"
"Changes will only take effect when reloaded."
msgstr ""
+"Adegan '% s' kini sedang diedit.\n"
+"Perubahan hanya akan berlaku apabila dimuat semula."
#: editor/dependency_editor.cpp
msgid ""
"Resource '%s' is in use.\n"
"Changes will only take effect when reloaded."
msgstr ""
+"Sumber '% s' sedang digunakan.\n"
+"Perubahan hanya akan berlaku apabila dimuat semula."
#: editor/dependency_editor.cpp
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "Dependencies"
-msgstr ""
+msgstr "Kebergantungan"
#: editor/dependency_editor.cpp
msgid "Resource"
-msgstr ""
+msgstr "Sumber"
#: editor/dependency_editor.cpp editor/editor_autoload_settings.cpp
#: editor/project_manager.cpp editor/project_settings_editor.cpp
msgid "Path"
-msgstr ""
+msgstr "Laluan"
#: editor/dependency_editor.cpp
msgid "Dependencies:"
-msgstr ""
+msgstr "Kebergantungan:"
#: editor/dependency_editor.cpp
msgid "Fix Broken"
-msgstr ""
+msgstr "Perbaiki Pecah"
#: editor/dependency_editor.cpp
msgid "Dependency Editor"
-msgstr ""
+msgstr "Editor Ketergantungan"
#: editor/dependency_editor.cpp
msgid "Search Replacement Resource:"
-msgstr ""
+msgstr "Cari Penggantian Sumber:"
#: editor/dependency_editor.cpp editor/editor_file_dialog.cpp
#: editor/editor_help_search.cpp editor/editor_node.cpp
@@ -1011,15 +1022,15 @@ msgstr ""
#: modules/visual_script/visual_script_property_selector.cpp
#: scene/gui/file_dialog.cpp
msgid "Open"
-msgstr ""
+msgstr "Buka"
#: editor/dependency_editor.cpp
msgid "Owners Of:"
-msgstr ""
+msgstr "Pemilik:"
#: editor/dependency_editor.cpp
msgid "Remove selected files from the project? (Can't be restored)"
-msgstr ""
+msgstr "Alih keluar fail terpilih dari projek? (Tidak dapat dipulihkan)"
#: editor/dependency_editor.cpp
msgid ""
@@ -1027,46 +1038,49 @@ msgid ""
"work.\n"
"Remove them anyway? (no undo)"
msgstr ""
+"Fail yang akan dikeluarkan diperlukan oleh sumber lain agar dapat "
+"berfungsi.\n"
+"Masih mahu keluarkan fail tersebut? (tidak boleh buat asal)"
#: editor/dependency_editor.cpp
msgid "Cannot remove:"
-msgstr ""
+msgstr "Tidak boleh dialih keluar:"
#: editor/dependency_editor.cpp
msgid "Error loading:"
-msgstr ""
+msgstr "Ralat memuatkan:"
#: editor/dependency_editor.cpp
msgid "Load failed due to missing dependencies:"
-msgstr ""
+msgstr "Gagal memuat kerana kebergantungan hilang:"
#: editor/dependency_editor.cpp editor/editor_node.cpp
msgid "Open Anyway"
-msgstr ""
+msgstr "Buka Bagaimanapun"
#: editor/dependency_editor.cpp
msgid "Which action should be taken?"
-msgstr ""
+msgstr "Tindakan apa yang harus diambil?"
#: editor/dependency_editor.cpp
msgid "Fix Dependencies"
-msgstr ""
+msgstr "Perbaiki Kebergantungan"
#: editor/dependency_editor.cpp
msgid "Errors loading!"
-msgstr ""
+msgstr "Ralat memuatkan!"
#: editor/dependency_editor.cpp
msgid "Permanently delete %d item(s)? (No undo!)"
-msgstr ""
+msgstr "Padamkan objek %d secara kekal? (Tidak boleh dibuat asal!)"
#: editor/dependency_editor.cpp
msgid "Show Dependencies"
-msgstr ""
+msgstr "Tunjuk Kebergantungan"
#: editor/dependency_editor.cpp
msgid "Orphan Resource Explorer"
-msgstr ""
+msgstr "Penjelajah Sumber Yatim"
#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
@@ -1074,79 +1088,89 @@ msgstr ""
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp
#: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp
msgid "Delete"
-msgstr ""
+msgstr "Padam"
#: editor/dependency_editor.cpp
msgid "Owns"
-msgstr ""
+msgstr "Memiliki"
#: editor/dependency_editor.cpp
msgid "Resources Without Explicit Ownership:"
-msgstr ""
+msgstr "Sumber Tanpa Hak Milik Eksplisit:"
#: editor/dictionary_property_edit.cpp
msgid "Change Dictionary Key"
-msgstr ""
+msgstr "Tukar Kunci Kamus"
#: editor/dictionary_property_edit.cpp
msgid "Change Dictionary Value"
-msgstr ""
+msgstr "Tukar Nilai Kamus"
#: editor/editor_about.cpp
msgid "Thanks from the Godot community!"
-msgstr ""
+msgstr "Terima kasih dari komuniti Godot!"
#: editor/editor_about.cpp
msgid "Godot Engine contributors"
-msgstr ""
+msgstr "Penyumbang Enjin Godot"
#: editor/editor_about.cpp
msgid "Project Founders"
-msgstr ""
+msgstr "Pengasas Projek"
#: editor/editor_about.cpp
msgid "Lead Developer"
-msgstr ""
+msgstr "Pemaju Utama"
#: editor/editor_about.cpp
msgid "Project Manager "
-msgstr ""
+msgstr "Pengurus Projek "
#: editor/editor_about.cpp
msgid "Developers"
-msgstr ""
+msgstr "Pemaju"
#: editor/editor_about.cpp
msgid "Authors"
-msgstr ""
+msgstr "Pengarang"
#: editor/editor_about.cpp
msgid "Platinum Sponsors"
-msgstr ""
+msgstr "Penaja Platinum"
#: editor/editor_about.cpp
msgid "Gold Sponsors"
-msgstr ""
+msgstr "Penaja Emas"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Penderma Perak"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Penderma Gangsa"
#: editor/editor_about.cpp
msgid "Mini Sponsors"
-msgstr ""
+msgstr "Penaja Mini"
#: editor/editor_about.cpp
msgid "Gold Donors"
-msgstr ""
+msgstr "Penderma Emas"
#: editor/editor_about.cpp
msgid "Silver Donors"
-msgstr ""
+msgstr "Penderma Perak"
#: editor/editor_about.cpp
msgid "Bronze Donors"
-msgstr ""
+msgstr "Penderma Gangsa"
#: editor/editor_about.cpp
msgid "Donors"
-msgstr ""
+msgstr "Penderma"
#: editor/editor_about.cpp
msgid "License"
@@ -1154,7 +1178,7 @@ msgstr "Lesen"
#: editor/editor_about.cpp
msgid "Third-party Licenses"
-msgstr ""
+msgstr "Lesen Pihak Ketiga"
#: editor/editor_about.cpp
msgid ""
@@ -1163,389 +1187,398 @@ msgid ""
"is an exhaustive list of all such third-party components with their "
"respective copyright statements and license terms."
msgstr ""
+"Enjin Godot bergantung kepada beberapa perpustakaan sumber terbuka dan bebas "
+"pihak ketiga, semuanya serasi dengan syarat-syarat lesen MITnya. Berikut "
+"adalah senarai lengkap semua komponen pihak ketiga tersebut dengan "
+"pernyataan hak cipta dan syarat lesen masing-masing."
#: editor/editor_about.cpp
msgid "All Components"
-msgstr ""
+msgstr "Semua Komponen"
#: editor/editor_about.cpp
msgid "Components"
-msgstr ""
+msgstr "Komponen"
#: editor/editor_about.cpp
msgid "Licenses"
-msgstr ""
+msgstr "Lesen"
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "Error opening package file, not in ZIP format."
-msgstr ""
+msgstr "Ralat semasa membuka fail pakej, bukan dalam format ZIP."
#: editor/editor_asset_installer.cpp
msgid "%s (Already Exists)"
-msgstr ""
+msgstr "%s (Sudah Wujud)"
#: editor/editor_asset_installer.cpp
msgid "Uncompressing Assets"
-msgstr ""
+msgstr "Nyahmampatkan Aset"
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "The following files failed extraction from package:"
-msgstr ""
+msgstr "Fail berikut gagal diekstrak dari pakej:"
#: editor/editor_asset_installer.cpp
msgid "And %s more files."
-msgstr ""
+msgstr "Dan sebanyak %s fail."
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "Package installed successfully!"
-msgstr ""
+msgstr "Pakej berjaya dipasang!"
#: editor/editor_asset_installer.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Success!"
-msgstr ""
+msgstr "Berjaya!"
#: editor/editor_asset_installer.cpp
msgid "Package Contents:"
-msgstr ""
+msgstr "Kandungan Pakej:"
#: editor/editor_asset_installer.cpp editor/editor_node.cpp
msgid "Install"
-msgstr ""
+msgstr "Pasang"
#: editor/editor_asset_installer.cpp
msgid "Package Installer"
-msgstr ""
+msgstr "Pemasang Pakej"
#: editor/editor_audio_buses.cpp
msgid "Speakers"
-msgstr ""
+msgstr "Pembesar suara"
#: editor/editor_audio_buses.cpp
msgid "Add Effect"
-msgstr ""
+msgstr "Tambah Kesan"
#: editor/editor_audio_buses.cpp
msgid "Rename Audio Bus"
-msgstr ""
+msgstr "Namakan Semula Bas Audio"
#: editor/editor_audio_buses.cpp
msgid "Change Audio Bus Volume"
-msgstr ""
+msgstr "Tukar Kelantangan Bas Audio"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Solo"
-msgstr ""
+msgstr "Togol Bas Audio Solo"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Mute"
-msgstr ""
+msgstr "Togol Senyap Bas Audio"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Bypass Effects"
-msgstr ""
+msgstr "Togol Kesan Pintasan Bas Audio"
#: editor/editor_audio_buses.cpp
msgid "Select Audio Bus Send"
-msgstr ""
+msgstr "Pilih Hantar Bas Audio"
#: editor/editor_audio_buses.cpp
msgid "Add Audio Bus Effect"
-msgstr ""
+msgstr "Tambah Kesan Bas Audio"
#: editor/editor_audio_buses.cpp
msgid "Move Bus Effect"
-msgstr ""
+msgstr "Alih Kesan Bas"
#: editor/editor_audio_buses.cpp
msgid "Delete Bus Effect"
-msgstr ""
+msgstr "Padam Kesan Bas"
#: editor/editor_audio_buses.cpp
msgid "Drag & drop to rearrange."
-msgstr ""
+msgstr "Seret & lepas untuk menyusun semula."
#: editor/editor_audio_buses.cpp
msgid "Solo"
-msgstr ""
+msgstr "Solo"
#: editor/editor_audio_buses.cpp
msgid "Mute"
-msgstr ""
+msgstr "Bisu"
#: editor/editor_audio_buses.cpp
msgid "Bypass"
-msgstr ""
+msgstr "Pintas"
#: editor/editor_audio_buses.cpp
msgid "Bus options"
-msgstr ""
+msgstr "Pilihan bas"
#: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "Duplicate"
-msgstr ""
+msgstr "Pendua"
#: editor/editor_audio_buses.cpp
msgid "Reset Volume"
-msgstr ""
+msgstr "Tetapkan Semula Kelantangan"
#: editor/editor_audio_buses.cpp
msgid "Delete Effect"
-msgstr ""
+msgstr "Padam Kesan"
#: editor/editor_audio_buses.cpp
msgid "Audio"
-msgstr ""
+msgstr "Audio"
#: editor/editor_audio_buses.cpp
msgid "Add Audio Bus"
-msgstr ""
+msgstr "Tambah Bas Audio"
#: editor/editor_audio_buses.cpp
msgid "Master bus can't be deleted!"
-msgstr ""
+msgstr "Bas induk tidak boleh dipadamkan!"
#: editor/editor_audio_buses.cpp
msgid "Delete Audio Bus"
-msgstr ""
+msgstr "Padam Bas Audio"
#: editor/editor_audio_buses.cpp
msgid "Duplicate Audio Bus"
-msgstr ""
+msgstr "Pendua Bas Audio"
#: editor/editor_audio_buses.cpp
msgid "Reset Bus Volume"
-msgstr ""
+msgstr "Tetapkan Semula Kelantangan Bas"
#: editor/editor_audio_buses.cpp
msgid "Move Audio Bus"
-msgstr ""
+msgstr "Pindah Bas Audio"
#: editor/editor_audio_buses.cpp
msgid "Save Audio Bus Layout As..."
-msgstr ""
+msgstr "Simpan Susun Atur Bas Audio Sebagai..."
#: editor/editor_audio_buses.cpp
msgid "Location for New Layout..."
-msgstr ""
+msgstr "Lokasi untuk Susun Atur Baru..."
#: editor/editor_audio_buses.cpp
msgid "Open Audio Bus Layout"
-msgstr ""
+msgstr "Buka Susun Atur Bas Audio"
#: editor/editor_audio_buses.cpp
msgid "There is no '%s' file."
-msgstr ""
+msgstr "Tiada fail '%s'."
#: editor/editor_audio_buses.cpp editor/plugins/canvas_item_editor_plugin.cpp
msgid "Layout"
-msgstr ""
+msgstr "Susun atur"
#: editor/editor_audio_buses.cpp
msgid "Invalid file, not an audio bus layout."
-msgstr ""
+msgstr "Fail tidak sah, bukan susun atur bas audio."
#: editor/editor_audio_buses.cpp
msgid "Error saving file: %s"
-msgstr ""
+msgstr "Ralat semasa menyimpan fail: %s"
#: editor/editor_audio_buses.cpp
msgid "Add Bus"
-msgstr ""
+msgstr "Tambah Bas"
#: editor/editor_audio_buses.cpp
msgid "Add a new Audio Bus to this layout."
-msgstr ""
+msgstr "Tambah Bas Audio baru ke susun atur ini."
#: editor/editor_audio_buses.cpp editor/editor_properties.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/property_editor.cpp
#: editor/script_create_dialog.cpp
msgid "Load"
-msgstr ""
+msgstr "Memuatkan"
#: editor/editor_audio_buses.cpp
msgid "Load an existing Bus Layout."
-msgstr ""
+msgstr "Muatkan Susun Atur Bas yang sedia ada."
#: editor/editor_audio_buses.cpp
msgid "Save As"
-msgstr ""
+msgstr "Simpan sebagai"
#: editor/editor_audio_buses.cpp
msgid "Save this Bus Layout to a file."
-msgstr ""
+msgstr "Simpan Susun Atur Bas ini ke fail."
#: editor/editor_audio_buses.cpp editor/import_dock.cpp
msgid "Load Default"
-msgstr ""
+msgstr "Muatkan Lalai"
#: editor/editor_audio_buses.cpp
msgid "Load the default Bus Layout."
-msgstr ""
+msgstr "Muatkan Susun Atur Bas lalai."
#: editor/editor_audio_buses.cpp
msgid "Create a new Bus Layout."
-msgstr ""
+msgstr "Cipta Susun Atur Bas baru."
#: editor/editor_autoload_settings.cpp
msgid "Invalid name."
-msgstr ""
+msgstr "Nama tidak sah."
#: editor/editor_autoload_settings.cpp
msgid "Valid characters:"
-msgstr ""
+msgstr "Watak yang sah:"
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing engine class name."
-msgstr ""
+msgstr "Tidak boleh bertembung dengan nama kelas engin yang telah wujud."
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing built-in type name."
msgstr ""
+"Tidak boleh bertembung dengan nama jenis terbina dalam yang telah wujud."
#: editor/editor_autoload_settings.cpp
msgid "Must not collide with an existing global constant name."
-msgstr ""
+msgstr "Tidak boleh bertembung dengan nama pemalar global yang telah wujud."
#: editor/editor_autoload_settings.cpp
msgid "Keyword cannot be used as an autoload name."
-msgstr ""
+msgstr "Kata kunci tidak boleh digunakan sebagai nama autoload."
#: editor/editor_autoload_settings.cpp
msgid "Autoload '%s' already exists!"
-msgstr ""
+msgstr "Autoload '%s' sudah wujud!"
#: editor/editor_autoload_settings.cpp
msgid "Rename Autoload"
-msgstr ""
+msgstr "Namakan Semula Autoload"
#: editor/editor_autoload_settings.cpp
msgid "Toggle AutoLoad Globals"
-msgstr ""
+msgstr "Togol Global Autoload"
#: editor/editor_autoload_settings.cpp
msgid "Move Autoload"
-msgstr ""
+msgstr "Pindah Autoload"
#: editor/editor_autoload_settings.cpp
msgid "Remove Autoload"
-msgstr ""
+msgstr "Keluarkan Autoload"
#: editor/editor_autoload_settings.cpp editor/editor_plugin_settings.cpp
msgid "Enable"
-msgstr ""
+msgstr "Aktifkan"
#: editor/editor_autoload_settings.cpp
msgid "Rearrange Autoloads"
-msgstr ""
+msgstr "Susun Semula Autoload"
#: editor/editor_autoload_settings.cpp
msgid "Can't add autoload:"
-msgstr ""
+msgstr "Tidak boleh menambahkan autoload:"
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
-msgstr ""
+msgstr "Tambah AutoLoad"
#: editor/editor_autoload_settings.cpp editor/editor_file_dialog.cpp
#: editor/editor_plugin_settings.cpp
#: editor/plugins/animation_tree_editor_plugin.cpp
#: editor/script_create_dialog.cpp scene/gui/file_dialog.cpp
msgid "Path:"
-msgstr ""
+msgstr "Laluan:"
#: editor/editor_autoload_settings.cpp
msgid "Node Name:"
-msgstr ""
+msgstr "Nama Nod:"
#: editor/editor_autoload_settings.cpp editor/editor_help_search.cpp
#: editor/editor_profiler.cpp editor/project_manager.cpp
#: editor/settings_config_dialog.cpp
msgid "Name"
-msgstr ""
+msgstr "Nama"
#: editor/editor_autoload_settings.cpp
msgid "Singleton"
-msgstr ""
+msgstr "Singleton"
#: editor/editor_data.cpp editor/inspector_dock.cpp
msgid "Paste Params"
-msgstr ""
+msgstr "Tampal Param"
#: editor/editor_data.cpp
msgid "Updating Scene"
-msgstr ""
+msgstr "Mengemaskini Adegan"
#: editor/editor_data.cpp
msgid "Storing local changes..."
-msgstr ""
+msgstr "Menyimpan perubahan tempatan..."
#: editor/editor_data.cpp
msgid "Updating scene..."
-msgstr ""
+msgstr "Mengemaskini adegan..."
#: editor/editor_data.cpp editor/editor_properties.cpp
msgid "[empty]"
-msgstr ""
+msgstr "[kosong]"
#: editor/editor_data.cpp
msgid "[unsaved]"
-msgstr ""
+msgstr "[tidak disimpan]"
#: editor/editor_dir_dialog.cpp
msgid "Please select a base directory first."
-msgstr ""
+msgstr "Sila pilih direktori asas terlebih dahulu."
#: editor/editor_dir_dialog.cpp
msgid "Choose a Directory"
-msgstr ""
+msgstr "Pilih Direktori"
#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp editor/project_manager.cpp
#: scene/gui/file_dialog.cpp
msgid "Create Folder"
-msgstr ""
+msgstr "Cipta Folder"
#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
#: editor/editor_plugin_settings.cpp editor/filesystem_dock.cpp
#: editor/plugins/theme_editor_plugin.cpp editor/project_export.cpp
#: modules/visual_script/visual_script_editor.cpp scene/gui/file_dialog.cpp
msgid "Name:"
-msgstr ""
+msgstr "Nama:"
#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp
#: editor/filesystem_dock.cpp scene/gui/file_dialog.cpp
msgid "Could not create folder."
-msgstr ""
+msgstr "Tidak dapat mencipta folder."
#: editor/editor_dir_dialog.cpp
msgid "Choose"
-msgstr ""
+msgstr "Pilih"
#: editor/editor_export.cpp
msgid "Storing File:"
-msgstr ""
+msgstr "Menyimpan Fail:"
#: editor/editor_export.cpp
msgid "No export template found at the expected path:"
-msgstr ""
+msgstr "Tiada templat eksport ditemui di laluan yang dijangkakan:"
#: editor/editor_export.cpp
msgid "Packing"
-msgstr ""
+msgstr "Pembungkusan"
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'ETC' texture compression for GLES2. Enable 'Import "
"Etc' in Project Settings."
msgstr ""
+"Platform sasaran memerlukan pemampatan tekstur 'ETC' untuk GLES2. Aktifkan "
+"'Import Etc' dalam Tetapan Projek."
#: editor/editor_export.cpp
msgid ""
"Target platform requires 'ETC2' texture compression for GLES3. Enable "
"'Import Etc 2' in Project Settings."
msgstr ""
+"Platform sasaran memerlukan pemampatan tekstur 'ETC2' untuk GLES3. Aktifkan "
+"'Import Etc 2' dalam Tetapan Projek."
#: editor/editor_export.cpp
msgid ""
@@ -1554,508 +1587,519 @@ msgid ""
"Enable 'Import Etc' in Project Settings, or disable 'Driver Fallback "
"Enabled'."
msgstr ""
+"Platform sasaran memerlukan pemampatan tekstur 'ETC' untuk sandaran pemandu "
+"ke GLES2.\n"
+"Aktifkan 'Import Etc' dalam Tetapan Projek, atau nyahaktifkan 'Driver "
+"Fallback Enabled'."
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
msgid "Custom debug template not found."
-msgstr ""
+msgstr "Templat nyahpepijat tersuai tidak dijumpai."
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
msgid "Custom release template not found."
-msgstr ""
+msgstr "Templat pelepasan tersuai tidak dijumpai."
#: editor/editor_export.cpp platform/javascript/export/export.cpp
msgid "Template file not found:"
-msgstr ""
+msgstr "Fail templat tidak dijumpai:"
#: editor/editor_export.cpp
msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."
msgstr ""
+"Pada eksport 32-bit PCK terbenam tidak boleh lebih besar daripada 4 GiB."
#: editor/editor_feature_profile.cpp
msgid "3D Editor"
-msgstr ""
+msgstr "Editor 3D"
#: editor/editor_feature_profile.cpp
msgid "Script Editor"
-msgstr ""
+msgstr "Editor Skrip"
#: editor/editor_feature_profile.cpp
msgid "Asset Library"
-msgstr ""
+msgstr "Perpustakaan Aset"
#: editor/editor_feature_profile.cpp
msgid "Scene Tree Editing"
-msgstr ""
+msgstr "Penyuntingan Pokok Adegan"
#: editor/editor_feature_profile.cpp
msgid "Import Dock"
-msgstr ""
+msgstr "Import Dok"
#: editor/editor_feature_profile.cpp
msgid "Node Dock"
-msgstr ""
+msgstr "Dok nod"
#: editor/editor_feature_profile.cpp
msgid "FileSystem and Import Docks"
-msgstr ""
+msgstr "Sistem Fail dan Dok Import"
#: editor/editor_feature_profile.cpp
msgid "Erase profile '%s'? (no undo)"
-msgstr ""
+msgstr "Padamkan profil '%s'? (tidak boleh buat asal)"
#: editor/editor_feature_profile.cpp
msgid "Profile must be a valid filename and must not contain '.'"
-msgstr ""
+msgstr "Profil mestilah nama fail yang sah dan tidak boleh mengandungi '.'"
#: editor/editor_feature_profile.cpp
msgid "Profile with this name already exists."
-msgstr ""
+msgstr "Profil dengan nama ini sudah wujud."
#: editor/editor_feature_profile.cpp
msgid "(Editor Disabled, Properties Disabled)"
-msgstr ""
+msgstr "(Editor Dinyahaktifkan, Ciri-ciri Dinyahaktifkan)"
#: editor/editor_feature_profile.cpp
msgid "(Properties Disabled)"
-msgstr ""
+msgstr "(Ciri-ciri dinyahaktif)"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "(Editor Disabled)"
-msgstr "Tidak Aktif"
+msgstr "(Editor Dinyahaktif)"
#: editor/editor_feature_profile.cpp
msgid "Class Options:"
-msgstr ""
+msgstr "Pilihan Kelas:"
#: editor/editor_feature_profile.cpp
msgid "Enable Contextual Editor"
-msgstr ""
+msgstr "Aktifkan Editor Kontekstual"
#: editor/editor_feature_profile.cpp
msgid "Enabled Properties:"
-msgstr ""
+msgstr "Ciri-ciri Diaktifkan:"
#: editor/editor_feature_profile.cpp
msgid "Enabled Features:"
-msgstr ""
+msgstr "Ciri Diaktifkan:"
#: editor/editor_feature_profile.cpp
msgid "Enabled Classes:"
-msgstr ""
+msgstr "Kelas Diaktifkan:"
#: editor/editor_feature_profile.cpp
msgid "File '%s' format is invalid, import aborted."
-msgstr ""
+msgstr "Format fail '%s' tidak sah, import dibatalkan."
#: editor/editor_feature_profile.cpp
msgid ""
"Profile '%s' already exists. Remove it first before importing, import "
"aborted."
msgstr ""
+"Profil '%s' sudah wujud. Keluarkannya terlebih dahulu sebelum mengimport, "
+"import dibatalkan."
#: editor/editor_feature_profile.cpp
msgid "Error saving profile to path: '%s'."
-msgstr ""
+msgstr "Ralat menyimpan profil ke laluan: '%s'."
#: editor/editor_feature_profile.cpp
msgid "Unset"
-msgstr ""
+msgstr "Nyahtetap"
#: editor/editor_feature_profile.cpp
msgid "Current Profile:"
-msgstr ""
+msgstr "Profil Semasa:"
#: editor/editor_feature_profile.cpp
msgid "Make Current"
-msgstr ""
+msgstr "Buat Semasa"
#: editor/editor_feature_profile.cpp
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/version_control_editor_plugin.cpp
msgid "New"
-msgstr ""
+msgstr "Baru"
#: editor/editor_feature_profile.cpp editor/editor_node.cpp
#: editor/project_manager.cpp
msgid "Import"
-msgstr ""
+msgstr "Import"
#: editor/editor_feature_profile.cpp editor/project_export.cpp
msgid "Export"
-msgstr ""
+msgstr "Eksport"
#: editor/editor_feature_profile.cpp
msgid "Available Profiles:"
-msgstr ""
+msgstr "Profil yang ada:"
#: editor/editor_feature_profile.cpp
msgid "Class Options"
-msgstr ""
+msgstr "Pilihan Kelas"
#: editor/editor_feature_profile.cpp
msgid "New profile name:"
-msgstr ""
+msgstr "Nama profil baru:"
#: editor/editor_feature_profile.cpp
msgid "Erase Profile"
-msgstr ""
+msgstr "Padam Profil"
#: editor/editor_feature_profile.cpp
msgid "Godot Feature Profile"
-msgstr ""
+msgstr "Profil Ciri Godot"
#: editor/editor_feature_profile.cpp
msgid "Import Profile(s)"
-msgstr ""
+msgstr "Import Profil"
#: editor/editor_feature_profile.cpp
msgid "Export Profile"
-msgstr ""
+msgstr "Eksport Profil"
#: editor/editor_feature_profile.cpp
msgid "Manage Editor Feature Profiles"
-msgstr ""
+msgstr "Urus Profil Ciri Editor"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Select Current Folder"
-msgstr ""
+msgstr "Pilih Folder Semasa"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "File Exists, Overwrite?"
-msgstr ""
+msgstr "Fail Wujud, Tulis Ganti?"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Select This Folder"
-msgstr ""
+msgstr "Pilih Folder Ini"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "Copy Path"
-msgstr ""
+msgstr "Salin Laluan"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "Open in File Manager"
-msgstr ""
+msgstr "Buka dalam Pengurus Fail"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
#: editor/filesystem_dock.cpp editor/project_manager.cpp
msgid "Show in File Manager"
-msgstr ""
+msgstr "Tunjukkan dalam Pengurus Fail"
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "New Folder..."
-msgstr ""
+msgstr "Folder Baru..."
#: editor/editor_file_dialog.cpp editor/find_in_files.cpp
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Refresh"
-msgstr ""
+msgstr "Muat Semula"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "All Recognized"
-msgstr ""
+msgstr "Semua Dikenali"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "All Files (*)"
-msgstr ""
+msgstr "Semua Fail (*)"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Open a File"
-msgstr ""
+msgstr "Buka Fail"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Open File(s)"
-msgstr ""
+msgstr "Buka Fail"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Open a Directory"
-msgstr ""
+msgstr "Buka Direktori"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Open a File or Directory"
-msgstr ""
+msgstr "Buka Fail atau Direktori"
#: editor/editor_file_dialog.cpp editor/editor_node.cpp
#: editor/editor_properties.cpp editor/inspector_dock.cpp
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp
msgid "Save"
-msgstr ""
+msgstr "Simpan"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Save a File"
-msgstr ""
+msgstr "Simpan Fail"
#: editor/editor_file_dialog.cpp
msgid "Go Back"
-msgstr ""
+msgstr "Pergi Balik"
#: editor/editor_file_dialog.cpp
msgid "Go Forward"
-msgstr ""
+msgstr "Pergi ke Hadapan"
#: editor/editor_file_dialog.cpp
msgid "Go Up"
-msgstr ""
+msgstr "Pergi Atas"
#: editor/editor_file_dialog.cpp
msgid "Toggle Hidden Files"
-msgstr ""
+msgstr "Togol Fail Tersembunyi"
#: editor/editor_file_dialog.cpp
msgid "Toggle Favorite"
-msgstr ""
+msgstr "Togol Kegemaran"
#: editor/editor_file_dialog.cpp
msgid "Toggle Mode"
-msgstr ""
+msgstr "Togol Mod"
#: editor/editor_file_dialog.cpp
msgid "Focus Path"
-msgstr ""
+msgstr "Laluan Fokus"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Up"
-msgstr ""
+msgstr "Pindah Kegemaran ke Atas"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Down"
-msgstr ""
+msgstr "Pindah Kegemaran ke Bawah"
#: editor/editor_file_dialog.cpp
msgid "Go to previous folder."
-msgstr ""
+msgstr "Pergi ke folder sebelumnya."
#: editor/editor_file_dialog.cpp
msgid "Go to next folder."
-msgstr ""
+msgstr "Pergi ke folder seterusnya."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Go to parent folder."
-msgstr ""
+msgstr "Pergi ke folder induk."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Refresh files."
-msgstr ""
+msgstr "Muat semula fail."
#: editor/editor_file_dialog.cpp
msgid "(Un)favorite current folder."
-msgstr ""
+msgstr "(Nyah)kegemaran folder semasa."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Toggle the visibility of hidden files."
-msgstr ""
+msgstr "Togol keterlihatan fail tersembunyi."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "View items as a grid of thumbnails."
-msgstr ""
+msgstr "Lihat barang sebagai grid gambar kecil."
#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp
msgid "View items as a list."
-msgstr ""
+msgstr "Lihat barang sebagai senarai."
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Directories & Files:"
-msgstr ""
+msgstr "Direktori & Fail:"
#: editor/editor_file_dialog.cpp editor/plugins/sprite_editor_plugin.cpp
#: editor/plugins/style_box_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp
msgid "Preview:"
-msgstr ""
+msgstr "Pratonton:"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "File:"
-msgstr ""
+msgstr "Fail:"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Must use a valid extension."
-msgstr ""
+msgstr "Mesti menggunakan sambungan yang sah."
#: editor/editor_file_system.cpp
msgid "ScanSources"
-msgstr ""
+msgstr "Sumber Imbas"
#: editor/editor_file_system.cpp
msgid ""
"There are multiple importers for different types pointing to file %s, import "
"aborted"
msgstr ""
+"Terdapat beberapa pengimport untuk pelbagai jenis yang menunjukkan ke fail "
+"%s, import dibatalkan"
#: editor/editor_file_system.cpp
msgid "(Re)Importing Assets"
-msgstr ""
+msgstr "Mengimport (Semula) Aset"
#: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp
msgid "Top"
-msgstr ""
+msgstr "Atas"
#: editor/editor_help.cpp
msgid "Class:"
-msgstr ""
+msgstr "Kelas:"
#: editor/editor_help.cpp editor/scene_tree_editor.cpp
#: editor/script_create_dialog.cpp
msgid "Inherits:"
-msgstr ""
+msgstr "Mewarisi:"
#: editor/editor_help.cpp
msgid "Inherited by:"
-msgstr ""
+msgstr "Diwarisi oleh:"
#: editor/editor_help.cpp
msgid "Description"
-msgstr ""
+msgstr "Keterangan"
#: editor/editor_help.cpp
msgid "Online Tutorials"
-msgstr ""
+msgstr "Tutorial Dalam Talian"
#: editor/editor_help.cpp
msgid "Properties"
-msgstr ""
+msgstr "Sifat"
#: editor/editor_help.cpp
msgid "override:"
-msgstr ""
+msgstr "ganti:"
#: editor/editor_help.cpp
msgid "default:"
-msgstr ""
+msgstr "lalai:"
#: editor/editor_help.cpp
msgid "Methods"
-msgstr ""
+msgstr "Kaedah"
#: editor/editor_help.cpp
msgid "Theme Properties"
-msgstr ""
+msgstr "Sifat Tema"
#: editor/editor_help.cpp
msgid "Enumerations"
-msgstr ""
+msgstr "Penghitungan"
#: editor/editor_help.cpp
msgid "Constants"
-msgstr ""
+msgstr "Pemalar"
#: editor/editor_help.cpp
msgid "Property Descriptions"
-msgstr ""
+msgstr "Penerangan Sifat"
#: editor/editor_help.cpp
msgid "(value)"
-msgstr ""
+msgstr "(nilai)"
#: editor/editor_help.cpp
msgid ""
"There is currently no description for this property. Please help us by "
"[color=$color][url=$url]contributing one[/url][/color]!"
msgstr ""
+"Tiada keterangan untuk sifat ini. Tolong bantu kami dengan [color=$color]"
+"[url=$url]menyumbang satu[/url][/color]!"
#: editor/editor_help.cpp
msgid "Method Descriptions"
-msgstr ""
+msgstr "Penerangan Kaedah"
#: editor/editor_help.cpp
msgid ""
"There is currently no description for this method. Please help us by [color="
"$color][url=$url]contributing one[/url][/color]!"
msgstr ""
+"Tiada keterangan untuk kaedah ini. Tolong bantu kami dengan [color=$color]"
+"[url=$url]menyumbang satu[/url][/color]!"
#: editor/editor_help_search.cpp editor/editor_node.cpp
#: editor/plugins/script_editor_plugin.cpp
msgid "Search Help"
-msgstr ""
+msgstr "Cari Bantuan"
#: editor/editor_help_search.cpp
msgid "Case Sensitive"
-msgstr ""
+msgstr "Kesensitifan Huruf"
#: editor/editor_help_search.cpp
msgid "Show Hierarchy"
-msgstr ""
+msgstr "Tunjuk Hierarki"
#: editor/editor_help_search.cpp
msgid "Display All"
-msgstr ""
+msgstr "Paparkan Semua"
#: editor/editor_help_search.cpp
msgid "Classes Only"
-msgstr ""
+msgstr "Kelas Sahaja"
#: editor/editor_help_search.cpp
msgid "Methods Only"
-msgstr ""
+msgstr "Kaedah Sahaja"
#: editor/editor_help_search.cpp
msgid "Signals Only"
-msgstr ""
+msgstr "Isyarat Sahaja"
#: editor/editor_help_search.cpp
msgid "Constants Only"
-msgstr ""
+msgstr "Pemalar Sahaja"
#: editor/editor_help_search.cpp
msgid "Properties Only"
-msgstr ""
+msgstr "Sifat Sahaja"
#: editor/editor_help_search.cpp
msgid "Theme Properties Only"
-msgstr ""
+msgstr "Sifat Tema Sahaja"
#: editor/editor_help_search.cpp
msgid "Member Type"
-msgstr ""
+msgstr "Jenis Ahli"
#: editor/editor_help_search.cpp
msgid "Class"
-msgstr ""
+msgstr "Kelas"
#: editor/editor_help_search.cpp
msgid "Method"
-msgstr ""
+msgstr "Kaedah"
#: editor/editor_help_search.cpp editor/plugins/script_text_editor.cpp
msgid "Signal"
-msgstr ""
+msgstr "Isyarat"
#: editor/editor_help_search.cpp editor/plugins/theme_editor_plugin.cpp
msgid "Constant"
-msgstr ""
+msgstr "Pemalar"
#: editor/editor_help_search.cpp
msgid "Property"
-msgstr ""
+msgstr "Sifat"
#: editor/editor_help_search.cpp
msgid "Theme Property"
-msgstr ""
+msgstr "Sifat Tema"
#: editor/editor_inspector.cpp editor/project_settings_editor.cpp
msgid "Property:"
-msgstr ""
+msgstr "Sifat:"
#: editor/editor_inspector.cpp
msgid "Set"
-msgstr ""
+msgstr "Tetapkan"
#: editor/editor_inspector.cpp
msgid "Set Multiple:"
-msgstr ""
+msgstr "Tetapkan Pelbagai:"
#: editor/editor_log.cpp
msgid "Output:"
-msgstr ""
+msgstr "Keluaran:"
#: editor/editor_log.cpp editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Copy Selection"
-msgstr "Semua Pilihan"
+msgstr "Salin Pilihan"
#: editor/editor_log.cpp editor/editor_network_profiler.cpp
#: editor/editor_profiler.cpp editor/editor_properties.cpp
@@ -2065,176 +2109,184 @@ msgstr "Semua Pilihan"
#: modules/gdnative/gdnative_library_editor_plugin.cpp scene/gui/line_edit.cpp
#: scene/gui/text_edit.cpp
msgid "Clear"
-msgstr ""
+msgstr "Kosongkan"
#: editor/editor_log.cpp
msgid "Clear Output"
-msgstr ""
+msgstr "Kosongkan Keluaran"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
#: editor/editor_profiler.cpp
msgid "Stop"
-msgstr ""
+msgstr "Hentikan"
#: editor/editor_network_profiler.cpp editor/editor_profiler.cpp
#: editor/plugins/animation_state_machine_editor.cpp editor/rename_dialog.cpp
msgid "Start"
-msgstr ""
+msgstr "Mulakan"
#: editor/editor_network_profiler.cpp
msgid "%s/s"
-msgstr ""
+msgstr "%s/s"
#: editor/editor_network_profiler.cpp
msgid "Down"
-msgstr ""
+msgstr "Bawah"
#: editor/editor_network_profiler.cpp
msgid "Up"
-msgstr ""
+msgstr "Atas"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
msgid "Node"
-msgstr ""
+msgstr "Nod"
#: editor/editor_network_profiler.cpp
msgid "Incoming RPC"
-msgstr ""
+msgstr "RPC masuk"
#: editor/editor_network_profiler.cpp
msgid "Incoming RSET"
-msgstr ""
+msgstr "RSET masuk"
#: editor/editor_network_profiler.cpp
msgid "Outgoing RPC"
-msgstr ""
+msgstr "RPC Keluar"
#: editor/editor_network_profiler.cpp
msgid "Outgoing RSET"
-msgstr ""
+msgstr "RSET Keluar"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "New Window"
-msgstr ""
+msgstr "Tetingkap Baru"
#: editor/editor_node.cpp
msgid "Imported resources can't be saved."
-msgstr ""
+msgstr "Sumber yang diimport tidak dapat disimpan."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
#: scene/gui/dialogs.cpp
msgid "OK"
-msgstr ""
+msgstr "OK"
#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Error saving resource!"
-msgstr ""
+msgstr "Ralat semasa menyimpan sumber!"
#: editor/editor_node.cpp
msgid ""
"This resource can't be saved because it does not belong to the edited scene. "
"Make it unique first."
msgstr ""
+"Sumber ini tidak dapat disimpan kerana tidak tergolong dalam adegan yang "
+"diedit. Jadikannya unik terlebih dahulu."
#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp
msgid "Save Resource As..."
-msgstr ""
+msgstr "Simpan Sumber Sebagai..."
#: editor/editor_node.cpp
msgid "Can't open file for writing:"
-msgstr ""
+msgstr "Tidak dapat membuka fail untuk ditulis:"
#: editor/editor_node.cpp
msgid "Requested file format unknown:"
-msgstr ""
+msgstr "Format fail yang diminta tidak diketahui:"
#: editor/editor_node.cpp
msgid "Error while saving."
-msgstr ""
+msgstr "Ralat semasa menyimpan."
#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp
msgid "Can't open '%s'. The file could have been moved or deleted."
msgstr ""
+"Tidak dapat membuka '% s'. Fail mungkin telah dipindahkan atau dipadam."
#: editor/editor_node.cpp
msgid "Error while parsing '%s'."
-msgstr ""
+msgstr "Ralat semasa menghuraikan '%s'."
#: editor/editor_node.cpp
msgid "Unexpected end of file '%s'."
-msgstr ""
+msgstr "Penghujung fail '%s' tidak dijangka."
#: editor/editor_node.cpp
msgid "Missing '%s' or its dependencies."
-msgstr ""
+msgstr "Hilang '%s' atau kebergantungannya."
#: editor/editor_node.cpp
msgid "Error while loading '%s'."
-msgstr ""
+msgstr "Ralat semasa memuatkan '%s'."
#: editor/editor_node.cpp
msgid "Saving Scene"
-msgstr ""
+msgstr "Menyimpan Adegan"
#: editor/editor_node.cpp
msgid "Analyzing"
-msgstr ""
+msgstr "Menganalisis"
#: editor/editor_node.cpp
msgid "Creating Thumbnail"
-msgstr ""
+msgstr "Mencipta Gambar Kecil"
#: editor/editor_node.cpp
msgid "This operation can't be done without a tree root."
-msgstr ""
+msgstr "Operasi ini tidak boleh dilakukan tanpa akar pokok."
#: editor/editor_node.cpp
msgid ""
"This scene can't be saved because there is a cyclic instancing inclusion.\n"
"Please resolve it and then attempt to save again."
msgstr ""
+"Adegan ini tidak dapat disimpan kerana terdapat penyertaan yang berbentuk "
+"siklik.\n"
+"Sila selesaikan dan kemudian cuba simpan semula."
#: editor/editor_node.cpp
msgid ""
"Couldn't save scene. Likely dependencies (instances or inheritance) couldn't "
"be satisfied."
msgstr ""
+"Tidak dapat menyimpan adegan. Kemungkinan kebergantungan (instance atau "
+"warisan) tidak dapat dipenuhi."
#: editor/editor_node.cpp editor/scene_tree_dock.cpp
msgid "Can't overwrite scene that is still open!"
-msgstr ""
+msgstr "Tidak boleh tulis ganti adegan yang masih terbuka!"
#: editor/editor_node.cpp
msgid "Can't load MeshLibrary for merging!"
-msgstr ""
+msgstr "Tidak dapat memuatkan MeshLibrary untuk penggabungan!"
#: editor/editor_node.cpp
msgid "Error saving MeshLibrary!"
-msgstr ""
+msgstr "Ralat menyimpan MeshLibrary!"
#: editor/editor_node.cpp
msgid "Can't load TileSet for merging!"
-msgstr ""
+msgstr "Tidak boleh memuatkan TileSet untuk penggabungan!"
#: editor/editor_node.cpp
msgid "Error saving TileSet!"
-msgstr ""
+msgstr "Ralat semasa menyimpan TileSet!"
#: editor/editor_node.cpp
msgid "Error trying to save layout!"
-msgstr ""
+msgstr "Ralat semasa menyimpan susun atur!"
#: editor/editor_node.cpp
msgid "Default editor layout overridden."
-msgstr ""
+msgstr "Susun atur lalai telah diganti."
#: editor/editor_node.cpp
msgid "Layout name not found!"
-msgstr ""
+msgstr "Nama susun atur tidak dijumpai!"
#: editor/editor_node.cpp
msgid "Restored default layout to base settings."
-msgstr ""
+msgstr "Tata letak lalai telah dipulihkan ke tetapan asas."
#: editor/editor_node.cpp
msgid ""
@@ -2242,18 +2294,26 @@ msgid ""
"Please read the documentation relevant to importing scenes to better "
"understand this workflow."
msgstr ""
+"Sumber ini tergolong dalam adegan yang diimport, maka ia tidak dapat "
+"diedit.\n"
+"Sila baca dokumentasi yang berkaitan dengan pengimportan adegan untuk lebih "
+"memahami aliran kerja ini."
#: editor/editor_node.cpp
msgid ""
"This resource belongs to a scene that was instanced or inherited.\n"
"Changes to it won't be kept when saving the current scene."
msgstr ""
+"Sumber ini tergolong dalam adegan yang di-instance atau diwarisi.\n"
+"Perubahan tidak akan disimpan semasa menyimpan adegan semasa."
#: editor/editor_node.cpp
msgid ""
"This resource was imported, so it's not editable. Change its settings in the "
"import panel and then re-import."
msgstr ""
+"Sumber ini telah diimport, maka ia tidak dapat diedit. Ubah tetapannya di "
+"panel import dan kemudian import semula."
#: editor/editor_node.cpp
msgid ""
@@ -2262,6 +2322,10 @@ msgid ""
"Please read the documentation relevant to importing scenes to better "
"understand this workflow."
msgstr ""
+"Adegan ini telah diimport, maka perubahan kepada ia tidak akan disimpan.\n"
+"Instance-kan ia atau mewarisi akan membenarkan perubahan dibuat padanya.\n"
+"Sila baca dokumentasi yang berkaitan dengan pengimportan adegan untuk lebih "
+"memahami aliran kerja ini."
#: editor/editor_node.cpp
msgid ""
@@ -2269,46 +2333,49 @@ msgid ""
"Please read the documentation relevant to debugging to better understand "
"this workflow."
msgstr ""
+"Ini adalah objek terpencil, maka perubahan padanya tidak akan disimpan.\n"
+"Sila baca dokumentasi yang berkaitan dengan penyahpepijatan untuk lebih "
+"memahami aliran kerja ini."
#: editor/editor_node.cpp
msgid "There is no defined scene to run."
-msgstr ""
+msgstr "Tiada adegan yang didefinisikan untuk dijalankan."
#: editor/editor_node.cpp
msgid "Could not start subprocess!"
-msgstr ""
+msgstr "Tidak dapat memulakan subproses!"
#: editor/editor_node.cpp editor/filesystem_dock.cpp
msgid "Open Scene"
-msgstr ""
+msgstr "Buka Adegan"
#: editor/editor_node.cpp
msgid "Open Base Scene"
-msgstr ""
+msgstr "Buka Adegan Asas"
#: editor/editor_node.cpp
msgid "Quick Open..."
-msgstr ""
+msgstr "Buka Cepat..."
#: editor/editor_node.cpp
msgid "Quick Open Scene..."
-msgstr ""
+msgstr "Buka Cepat Adegan..."
#: editor/editor_node.cpp
msgid "Quick Open Script..."
-msgstr ""
+msgstr "Buka Cepat Skrip..."
#: editor/editor_node.cpp
msgid "Save & Close"
-msgstr ""
+msgstr "Simpan & Tutup"
#: editor/editor_node.cpp
msgid "Save changes to '%s' before closing?"
-msgstr ""
+msgstr "Simpan perubahan pada '%s' sebelum menutup?"
#: editor/editor_node.cpp
msgid "Saved %s modified resource(s)."
-msgstr ""
+msgstr "Sumber %s yang diubahsuai telah disimpan."
#: editor/editor_node.cpp
msgid "A root node is required to save the scene."
@@ -2758,9 +2825,8 @@ msgid "Editor"
msgstr ""
#: editor/editor_node.cpp
-#, fuzzy
msgid "Editor Settings..."
-msgstr "Set Peralihan ke:"
+msgstr "Tetapan Editor..."
#: editor/editor_node.cpp
msgid "Editor Layout"
@@ -4064,9 +4130,8 @@ msgstr ""
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
-#, fuzzy
msgid "Add Animation Point"
-msgstr "Set Peralihan ke:"
+msgstr "Tambah Titik Animasi"
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Remove BlendSpace1D Point"
@@ -4209,9 +4274,8 @@ msgid "Nodes Disconnected"
msgstr ""
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Set Animation"
-msgstr "Set Peralihan ke:"
+msgstr "Tetapkan Animasi"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
@@ -4391,9 +4455,8 @@ msgid "Animation"
msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "Edit Transitions..."
-msgstr "Set Peralihan ke:"
+msgstr "Sunting Peralihan..."
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Open in Inspector"
@@ -4491,14 +4554,12 @@ msgid "Move Node"
msgstr ""
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Transition exists!"
-msgstr "Set Peralihan ke:"
+msgstr "Peralihan wujud!"
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Add Transition"
-msgstr "Set Peralihan ke:"
+msgstr "Tambah Peralihan"
#: editor/plugins/animation_state_machine_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
@@ -4538,9 +4599,8 @@ msgid "Node Removed"
msgstr ""
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Transition Removed"
-msgstr "Set Peralihan ke:"
+msgstr "Peralihan Dikeluarkan"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Set Start Node (Autoplay)"
@@ -4574,9 +4634,8 @@ msgid "Set the end animation. This is useful for sub-transitions."
msgstr ""
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Transition: "
-msgstr "Set Peralihan ke:"
+msgstr "Peralihan: "
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Play Mode:"
@@ -5621,9 +5680,8 @@ msgid "Load Curve Preset"
msgstr ""
#: editor/plugins/curve_editor_plugin.cpp
-#, fuzzy
msgid "Add Point"
-msgstr "Set Peralihan ke:"
+msgstr "Tambah Titik"
#: editor/plugins/curve_editor_plugin.cpp
#, fuzzy
@@ -8065,9 +8123,8 @@ msgid ""
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete selected Rect."
-msgstr "Semua Pilihan"
+msgstr "Padam Rect yang dipilih."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid ""
@@ -8076,9 +8133,8 @@ msgid ""
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Delete polygon."
-msgstr "Semua Pilihan"
+msgstr "Padam poligon."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid ""
@@ -8477,9 +8533,8 @@ msgid "Color constant."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Color uniform."
-msgstr "Anim Ubah Penukaran"
+msgstr "Warna seragam."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the boolean result of the %s comparison between two parameters."
@@ -8822,9 +8877,8 @@ msgid "Scalar constant."
msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Scalar uniform."
-msgstr "Anim Ubah Penukaran"
+msgstr "Seragam skalar."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Perform the cubic texture lookup."
@@ -10177,14 +10231,12 @@ msgid "Make node as Root"
msgstr ""
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete %d nodes and any children?"
-msgstr "Semua Pilihan"
+msgstr "Padamkan nod %d dan mana-mana kanak-kanak?"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete %d nodes?"
-msgstr "Semua Pilihan"
+msgstr "Padam nod %d?"
#: editor/scene_tree_dock.cpp
msgid "Delete the root node \"%s\"?"
@@ -10195,9 +10247,8 @@ msgid "Delete node \"%s\" and its children?"
msgstr ""
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete node \"%s\"?"
-msgstr "Semua Pilihan"
+msgstr "Padam nod \"%s\"?"
#: editor/scene_tree_dock.cpp
msgid "Can not perform with the root node."
@@ -11172,9 +11223,8 @@ msgid "Set Variable Type"
msgstr ""
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Input Port"
-msgstr "Set Peralihan ke:"
+msgstr "Tambah Port Input"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Output Port"
@@ -11419,9 +11469,8 @@ msgid "Add Nodes..."
msgstr ""
#: modules/visual_script/visual_script_editor.cpp
-#, fuzzy
msgid "Add Function..."
-msgstr "Semua Pilihan"
+msgstr "Tambah fungsi..."
#: modules/visual_script/visual_script_editor.cpp
msgid "function_name"
diff --git a/editor/translations/nb.po b/editor/translations/nb.po
index dbad564d9a..7837db5c53 100644
--- a/editor/translations/nb.po
+++ b/editor/translations/nb.po
@@ -1199,6 +1199,16 @@ msgid "Gold Sponsors"
msgstr "Gullsponsorer"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Sølvdonorer"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Bronsedonorer"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Minisponsorer"
diff --git a/editor/translations/nl.po b/editor/translations/nl.po
index 7f111ad901..ac5761f63d 100644
--- a/editor/translations/nl.po
+++ b/editor/translations/nl.po
@@ -47,8 +47,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-07-04 08:58+0000\n"
-"Last-Translator: marnicq van loon <marnicqvanloon@gmail.com>\n"
+"PO-Revision-Date: 2020-08-28 13:09+0000\n"
+"Last-Translator: Stijn Hinlopen <f.a.hinlopen@gmail.com>\n"
"Language-Team: Dutch <https://hosted.weblate.org/projects/godot-engine/godot/"
"nl/>\n"
"Language: nl\n"
@@ -56,7 +56,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.2-dev\n"
+"X-Generator: Weblate 4.2.1-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1181,6 +1181,16 @@ msgid "Gold Sponsors"
msgstr "Gouden Sponsors"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Zilveren Donors"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Bronzen Donors"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Mini Sponsoren"
@@ -7361,7 +7371,7 @@ msgstr "Bekijk Omgeving"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Gizmos"
-msgstr "Bekijk Gizmos"
+msgstr "Toon Gizmos"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Information"
@@ -7450,9 +7460,9 @@ msgid ""
msgstr ""
"Klik om te wisselen tussen zichtbaarheidsweergaven.\n"
"\n"
-"Open oog: handvat is zichtbaar.\n"
-"Gesloten oog: handvat is verborgen.\n"
-"Half open oog: handvat is ook zichtbaar door ondoorzichtige oppervlaktes."
+"Open oog: Gizmo is zichtbaar.\n"
+"Gesloten oog: Gizmo is verborgen.\n"
+"Half open oog: Gizmo is ook zichtbaar door ondoorzichtige oppervlaktes."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Nodes To Floor"
@@ -7640,7 +7650,7 @@ msgstr "Post"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Nameless gizmo"
-msgstr "Naamloos apparaat"
+msgstr "Naamloze gizmo"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Create Mesh2D"
@@ -10596,9 +10606,8 @@ msgid "Make node as Root"
msgstr "Knoop tot wortelknoop maken"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete %d nodes and any children?"
-msgstr "Verwijder knoop \"%s\" en zijn kinderen?"
+msgstr "%d knopen en hun (eventuele) kinderen verwijderen?"
#: editor/scene_tree_dock.cpp
msgid "Delete %d nodes?"
diff --git a/editor/translations/or.po b/editor/translations/or.po
index 5859fe6b0a..9bb6ba7410 100644
--- a/editor/translations/or.po
+++ b/editor/translations/or.po
@@ -1105,6 +1105,14 @@ msgid "Gold Sponsors"
msgstr ""
#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr ""
diff --git a/editor/translations/pl.po b/editor/translations/pl.po
index d7ff515b05..6d7265c085 100644
--- a/editor/translations/pl.po
+++ b/editor/translations/pl.po
@@ -41,12 +41,13 @@
# Jan Ligudziński <jan.ligudzinski@gmail.com>, 2020.
# Adam Jagoda <kontakt@lukasz.xyz>, 2020.
# Filip Glura <mcmr.slendy@gmail.com>, 2020.
+# Roman Skiba <romanskiba0@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-07-31 03:47+0000\n"
-"Last-Translator: Tomek <kobewi4e@gmail.com>\n"
+"PO-Revision-Date: 2020-09-01 18:42+0000\n"
+"Last-Translator: Roman Skiba <romanskiba0@gmail.com>\n"
"Language-Team: Polish <https://hosted.weblate.org/projects/godot-engine/"
"godot/pl/>\n"
"Language: pl\n"
@@ -55,7 +56,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.2-dev\n"
+"X-Generator: Weblate 4.2.1-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1172,6 +1173,16 @@ msgid "Gold Sponsors"
msgstr "Złoci sponsorzy"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Srebrni darczyńcy"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Brązowi darczyńcy"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Mini-sponsorzy"
@@ -9539,7 +9550,7 @@ msgstr "Plik paczki"
#: editor/project_export.cpp
msgid "Features"
-msgstr "Funkcjonalności"
+msgstr "Funkcje"
#: editor/project_export.cpp
msgid "Custom (comma-separated):"
diff --git a/editor/translations/pr.po b/editor/translations/pr.po
index bf2d3ef0ad..d03994f21a 100644
--- a/editor/translations/pr.po
+++ b/editor/translations/pr.po
@@ -1148,6 +1148,14 @@ msgid "Gold Sponsors"
msgstr ""
#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr ""
diff --git a/editor/translations/pt_BR.po b/editor/translations/pt_BR.po
index 6c035decd5..510cbdee51 100644
--- a/editor/translations/pt_BR.po
+++ b/editor/translations/pt_BR.po
@@ -1230,6 +1230,16 @@ msgid "Gold Sponsors"
msgstr "Patrocinadores Ouro"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Doadores Prata"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Doadores Bronze"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Patrocinadores Mini"
diff --git a/editor/translations/pt_PT.po b/editor/translations/pt_PT.po
index b9d6c82ff0..489a8012f5 100644
--- a/editor/translations/pt_PT.po
+++ b/editor/translations/pt_PT.po
@@ -13,15 +13,15 @@
# Rueben Stevens <supercell03@gmail.com>, 2017.
# SARDON <fabio3_Santos@hotmail.com>, 2017.
# Vinicius Gonçalves <viniciusgoncalves21@gmail.com>, 2017.
-# ssantos <ssantos@web.de>, 2018, 2019.
+# ssantos <ssantos@web.de>, 2018, 2019, 2020.
# Gonçalo Dinis Guerreiro João <goncalojoao205@gmail.com>, 2019.
# Manuela Silva <mmsrs@sky.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-07-31 03:47+0000\n"
-"Last-Translator: João Lopes <linux-man@hotmail.com>\n"
+"PO-Revision-Date: 2020-08-16 15:25+0000\n"
+"Last-Translator: ssantos <ssantos@web.de>\n"
"Language-Team: Portuguese (Portugal) <https://hosted.weblate.org/projects/"
"godot-engine/godot/pt_PT/>\n"
"Language: pt_PT\n"
@@ -1037,7 +1037,7 @@ msgstr "Proprietários de:"
#: editor/dependency_editor.cpp
msgid "Remove selected files from the project? (Can't be restored)"
-msgstr "Remover arquivos selecionados do Projeto? (Sem desfazer)"
+msgstr "Remover ficheiros selecionados do Projeto? (Sem desfazer)"
#: editor/dependency_editor.cpp
msgid ""
@@ -1045,7 +1045,7 @@ msgid ""
"work.\n"
"Remove them anyway? (no undo)"
msgstr ""
-"Os arquivos a serem removidos são necessários para que outros recursos "
+"Os ficheiros a serem removidos são necessários para que outros recursos "
"funcionem.\n"
"Remover mesmo assim? (sem anular)"
@@ -1150,6 +1150,16 @@ msgid "Gold Sponsors"
msgstr "Patrocinadores Gold"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Doadores Silver"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Doadores Bronze"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Patrocinadores Mini"
@@ -1403,11 +1413,11 @@ msgstr "Guardar este Modelo de Barramento para um ficheiro."
#: editor/editor_audio_buses.cpp editor/import_dock.cpp
msgid "Load Default"
-msgstr "Carregar Padrão"
+msgstr "Carregar Predefinição"
#: editor/editor_audio_buses.cpp
msgid "Load the default Bus Layout."
-msgstr "Carregar o Modelo padrão de barramento."
+msgstr "Carregar o Modelo predefinido de barramento."
#: editor/editor_audio_buses.cpp
msgid "Create a new Bus Layout."
@@ -1551,7 +1561,7 @@ msgstr "Escolha"
#: editor/editor_export.cpp
msgid "Storing File:"
-msgstr "Arquivo de Armazenamento:"
+msgstr "Armazenar o Ficheiro:"
#: editor/editor_export.cpp
msgid "No export template found at the expected path:"
@@ -1962,7 +1972,7 @@ msgstr "Sobrepõe:"
#: editor/editor_help.cpp
msgid "default:"
-msgstr "Padrão:"
+msgstr "predefinição:"
#: editor/editor_help.cpp
msgid "Methods"
@@ -2273,7 +2283,7 @@ msgstr "Erro ao tentar guardar o Modelo!"
#: editor/editor_node.cpp
msgid "Default editor layout overridden."
-msgstr "O Modelo do Editor padrão foi substituído."
+msgstr "O modelo do editor predefinido foi substituído."
#: editor/editor_node.cpp
msgid "Layout name not found!"
@@ -2281,7 +2291,7 @@ msgstr "Nome do Modelo não encontrado!"
#: editor/editor_node.cpp
msgid "Restored default layout to base settings."
-msgstr "Modelo padrão restaurado para as configurações base."
+msgstr "Modelo predefinido restaurado para as configurações base."
#: editor/editor_node.cpp
msgid ""
@@ -2582,7 +2592,7 @@ msgstr "Apagar Modelo"
#: editor/editor_node.cpp editor/import_dock.cpp
#: editor/script_create_dialog.cpp
msgid "Default"
-msgstr "Padrão"
+msgstr "Predefinição"
#: editor/editor_node.cpp editor/editor_properties.cpp
#: editor/plugins/script_editor_plugin.cpp editor/property_editor.cpp
@@ -2840,7 +2850,7 @@ msgid ""
msgstr ""
"Com esta opção ativa, alterações da cena no editor serão replicadas no jogo "
"em execução.\n"
-"Quando usada num dispositivo remoto, é mais eficiente com um sistema de "
+"Quando usada num aparelho remoto, é mais eficiente com um sistema de "
"ficheiros em rede."
#: editor/editor_node.cpp
@@ -2856,7 +2866,7 @@ msgid ""
msgstr ""
"Com esta opção ativa, qualquer Script guardado será recarregado no jogo em "
"execução.\n"
-"Quando usada num dispositivo remoto, é mais eficiente com um Sistema de "
+"Quando usada num aparelho remoto, é mais eficiente com um Sistema de "
"Ficheiros em rede."
#: editor/editor_node.cpp editor/script_create_dialog.cpp
@@ -3464,8 +3474,9 @@ msgid ""
"No download links found for this version. Direct download is only available "
"for official releases."
msgstr ""
-"Não foram encontrados ligações para download para esta versão. Download "
-"direto está apenas disponível para os lançamentos oficiais."
+"Não foram encontrados ligações para descarregar para esta versão. "
+"Descarregamentos diretos estão disponíveis apenas para os lançamentos "
+"oficiais."
#: editor/export_template_manager.cpp
#: editor/plugins/asset_library_editor_plugin.cpp
@@ -3981,11 +3992,11 @@ msgstr "%d Ficheiros"
#: editor/import_dock.cpp
msgid "Set as Default for '%s'"
-msgstr "Definir como Padrão para '%s'"
+msgstr "Definir como Predefinição para '%s'"
#: editor/import_dock.cpp
msgid "Clear Default for '%s'"
-msgstr "Limpar Padrão para '%s'"
+msgstr "Limpar Predefinição para '%s'"
#: editor/import_dock.cpp
msgid "Import As:"
@@ -5658,7 +5669,7 @@ msgstr "Erro a instanciar cena de %s"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Change Default Type"
-msgstr "Mudar Tipo Padrão"
+msgstr "Mudar Predefinição de Tipo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
@@ -8577,7 +8588,7 @@ msgstr "Definir Nome do Uniform"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Set Input Default Port"
-msgstr "Definir Porta de Entrada Padrão"
+msgstr "Definir Porta de Entrada Predefinida"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Add Node to Visual Shader"
@@ -9306,7 +9317,7 @@ msgid ""
"constants."
msgstr ""
"Expressão personalizada em Linguagem Godot Shader, colocada sobre o shader "
-"resultante. Pode colocar várias definições de função e chamá-las depois nas "
+"resultante. Pode pôr várias definições de função e chamá-las depois nas "
"Expressões. Também pode declarar variantes, uniformes e constantes."
#: editor/plugins/visual_shader_editor_plugin.cpp
@@ -9965,11 +9976,11 @@ msgstr "Adicionar evento ação de entrada"
#: editor/project_settings_editor.cpp
msgid "All Devices"
-msgstr "Todos os Dispositivos"
+msgstr "Todos os Aparelhos"
#: editor/project_settings_editor.cpp
msgid "Device"
-msgstr "Dispositivo"
+msgstr "Aparelho"
#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp
msgid "Press a Key..."
@@ -10181,7 +10192,7 @@ msgstr "Zona morta"
#: editor/project_settings_editor.cpp
msgid "Device:"
-msgstr "Dispositivo:"
+msgstr "Aparelho:"
#: editor/project_settings_editor.cpp
msgid "Index:"
@@ -10425,11 +10436,11 @@ msgstr "No carácter %s"
#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
msgid "Reparent Node"
-msgstr "Recolocar Nó"
+msgstr "Repôr Nó"
#: editor/reparent_dialog.cpp
msgid "Reparent Location (Select new Parent):"
-msgstr "Recolocar localização (selecionar novo Parente):"
+msgstr "Repôr localização (selecionar novo Parente):"
#: editor/reparent_dialog.cpp
msgid "Keep Global Transform"
@@ -10437,7 +10448,7 @@ msgstr "Manter transformação global"
#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp
msgid "Reparent"
-msgstr "Recolocar"
+msgstr "Repôr"
#: editor/run_settings_dialog.cpp
msgid "Run Mode:"
@@ -10562,7 +10573,7 @@ msgid ""
"reverted to their default."
msgstr ""
"Desativar \"editable_instance\" irá reverter todas as propriedades do nó "
-"para os seus valores padrão."
+"para os seus valores predefinição."
#: editor/scene_tree_dock.cpp
msgid ""
@@ -10570,7 +10581,8 @@ msgid ""
"cause all properties of the node to be reverted to their default."
msgstr ""
"Ativar \"Carregar como Espaço Reservado\" vai desativar \"Filhos Editáveis\" "
-"e fazer com que todas as propriedades do nó revertam para valores padrão."
+"e fazer com que todas as propriedades do nó revertam para valores "
+"predefinidos."
#: editor/scene_tree_dock.cpp
msgid "Make Local"
@@ -10680,7 +10692,7 @@ msgstr "Mudar tipo"
#: editor/scene_tree_dock.cpp
msgid "Reparent to New Node"
-msgstr "Recolocar o Novo Nó"
+msgstr "Repôr o Novo Nó"
#: editor/scene_tree_dock.cpp
msgid "Make Scene Root"
@@ -11539,7 +11551,7 @@ msgstr "Mudar nome do argumento"
#: modules/visual_script/visual_script_editor.cpp
msgid "Set Variable Default Value"
-msgstr "Definir Valor Padrão da Variável"
+msgstr "Definir Valor Predefinido da Variável"
#: modules/visual_script/visual_script_editor.cpp
msgid "Set Variable Type"
@@ -11931,7 +11943,7 @@ msgstr "O pacote deve ter pelo menos um separador '.'."
#: platform/android/export/export.cpp
msgid "Select device from the list"
-msgstr "Selecionar dispositivo da lista"
+msgstr "Selecionar aparelho da lista"
#: platform/android/export/export.cpp
msgid "ADB executable not configured in the Editor Settings."
@@ -12083,7 +12095,7 @@ msgstr "Executar no Navegador"
#: platform/javascript/export/export.cpp
msgid "Run exported HTML in the system's default browser."
-msgstr "Executar HTML exportado no Navegador padrão do sistema."
+msgstr "Executar HTML exportado no navegador predefinido do sistema."
#: platform/javascript/export/export.cpp
msgid "Could not write file:"
@@ -12107,7 +12119,7 @@ msgstr "Não consigo ler ficheiro de imagem do ecrã de inicialização:"
#: platform/javascript/export/export.cpp
msgid "Using default boot splash image."
-msgstr "A usar imagem padrão de inicialização."
+msgstr "A usar imagem de inicialização predefinida."
#: platform/uwp/export/export.cpp
msgid "Invalid package short name."
@@ -12333,7 +12345,7 @@ msgstr ""
#: scene/2d/skeleton_2d.cpp
msgid "This Bone2D chain should end at a Skeleton2D node."
-msgstr "Esta corrente de Bone2D deve terminar em um nó Skeleton2D."
+msgstr "Esta corrente de Bone2D deve terminar num nó Skeleton2D."
#: scene/2d/skeleton_2d.cpp
msgid "A Bone2D only works with a Skeleton2D or another Bone2D as parent node."
@@ -12754,7 +12766,7 @@ msgid ""
"Default Environment as specified in Project Settings (Rendering -> "
"Environment -> Default Environment) could not be loaded."
msgstr ""
-"Ambiente Padrão especificado em Configuração do Projeto (Rendering -> "
+"Ambiente predefinido especificado em Configuração do Projeto (Rendering -> "
"Environment -> Default Environment) não pode ser carregado."
#: scene/main/viewport.cpp
diff --git a/editor/translations/ro.po b/editor/translations/ro.po
index 29487392f8..ef64a09d92 100644
--- a/editor/translations/ro.po
+++ b/editor/translations/ro.po
@@ -1147,6 +1147,16 @@ msgid "Gold Sponsors"
msgstr "Sponsori Aur"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Donatori de Argint"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Donatori de Bronz"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Mini Sponsori"
diff --git a/editor/translations/ru.po b/editor/translations/ru.po
index 7b12d8195c..71711ad333 100644
--- a/editor/translations/ru.po
+++ b/editor/translations/ru.po
@@ -85,12 +85,13 @@
# kyanukovich <ianu0001@algonquinlive.com>, 2020.
# Ron788 <ustinov200511@gmail.com>, 2020.
# Daniel <dan.ef1999@gmail.com>, 2020.
+# NeoLan Qu <it.bulla@mail.ru>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-08-01 11:14+0000\n"
-"Last-Translator: Daniel <dan.ef1999@gmail.com>\n"
+"PO-Revision-Date: 2020-08-15 09:32+0000\n"
+"Last-Translator: Danil Alexeev <danil@alexeev.xyz>\n"
"Language-Team: Russian <https://hosted.weblate.org/projects/godot-engine/"
"godot/ru/>\n"
"Language: ru\n"
@@ -1218,6 +1219,16 @@ msgid "Gold Sponsors"
msgstr "Золотые ÑпонÑоры"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "СеребрÑные доноры"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Бронзовые доноры"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Мини ÑпонÑоры"
@@ -8952,7 +8963,7 @@ msgstr "Возвращает обратный гиперболичеÑкий Ñ‚Ð
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
"Finds the nearest integer that is greater than or equal to the parameter."
-msgstr "ВычиÑлÑет ближайшее целое чиÑло, большее или равное аргументу."
+msgstr "Ðаходит ближайшее целое, которое больше или равно параметра."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Constrains a value to lie between two further values."
@@ -8960,11 +8971,11 @@ msgstr "Удерживает значение в пределах двух дрÑ
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the cosine of the parameter."
-msgstr "Возвращает коÑÐ¸Ð½ÑƒÑ Ð°Ñ€Ð³ÑƒÐ¼ÐµÐ½Ñ‚Ð°."
+msgstr "Возвращает коÑÐ¸Ð½ÑƒÑ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð°."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the hyperbolic cosine of the parameter."
-msgstr "Возвращает гиперболичеÑкий коÑÐ¸Ð½ÑƒÑ Ð°Ñ€Ð³ÑƒÐ¼ÐµÐ½Ñ‚Ð°."
+msgstr "Возвращает гиперболичеÑкий коÑÐ¸Ð½ÑƒÑ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð°."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Converts a quantity in radians to degrees."
@@ -8980,7 +8991,7 @@ msgstr "ЭкÑпонента Ñ Ð¾Ñнованием 2."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the nearest integer less than or equal to the parameter."
-msgstr "ВычиÑлÑет ближайшее целое, меньшее или равное аргументу."
+msgstr "Ðаходит ближайшее целое, меньшее или равное аргументу."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Computes the fractional part of the argument."
@@ -8988,7 +8999,7 @@ msgstr "ВычиÑлÑет дробную чаÑть аргумента."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the inverse of the square root of the parameter."
-msgstr "Возвращает обратный корень из аргумента."
+msgstr "Возвращает обратный квадратный корень из аргумента."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Natural logarithm."
@@ -9033,11 +9044,11 @@ msgstr "1.0 / ÑкалÑÑ€"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the nearest integer to the parameter."
-msgstr "ВычиÑлÑет ближайшее целое чиÑло."
+msgstr "Ðаходит ближайшее к параметру целое чиÑло."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Finds the nearest even integer to the parameter."
-msgstr "ВычиÑлÑет ближайшее чётное чиÑло."
+msgstr "Ðаходит ближайшее чётное чиÑло к параметру."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Clamps the value between 0.0 and 1.0."
diff --git a/editor/translations/si.po b/editor/translations/si.po
index c8b0a57cbe..2ca3642fce 100644
--- a/editor/translations/si.po
+++ b/editor/translations/si.po
@@ -1128,6 +1128,14 @@ msgid "Gold Sponsors"
msgstr ""
#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr ""
diff --git a/editor/translations/sk.po b/editor/translations/sk.po
index 59cd8da671..13482d4c59 100644
--- a/editor/translations/sk.po
+++ b/editor/translations/sk.po
@@ -14,7 +14,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-06-15 01:48+0000\n"
+"PO-Revision-Date: 2020-09-04 06:51+0000\n"
"Last-Translator: Richard Urban <redasuio1@gmail.com>\n"
"Language-Team: Slovak <https://hosted.weblate.org/projects/godot-engine/"
"godot/sk/>\n"
@@ -23,7 +23,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.3-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -32,7 +32,7 @@ msgstr "Chybný argument convert(), použite TYPE_* konštanty."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
-msgstr "dĺžka oÄakávaného stringu 1 (písmeno)"
+msgstr "dĺžka oÄakávaného stringu 1 (písmeno)."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
@@ -42,7 +42,7 @@ msgstr "Nedostatok bajtov na dekódovanie, alebo chybný formát."
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
-msgstr "Neplatný vstup %i (neprešlo) vo výraze"
+msgstr "Nesprávny vstup(input) %i (neschválený) v požiadavke"
#: core/math/expression.cpp
msgid "self can't be used because instance is null (not passed)"
@@ -98,7 +98,7 @@ msgstr "EiB"
#: editor/animation_bezier_editor.cpp
msgid "Free"
-msgstr "zadarmo"
+msgstr "Voľný"
#: editor/animation_bezier_editor.cpp
msgid "Balanced"
@@ -118,7 +118,7 @@ msgstr "Hodnota:"
#: editor/animation_bezier_editor.cpp
msgid "Insert Key Here"
-msgstr "Sem Vložte KľúÄ"
+msgstr "Tu vložiÅ¥ kľúÄ"
#: editor/animation_bezier_editor.cpp
msgid "Duplicate Selected Key(s)"
@@ -130,7 +130,7 @@ msgstr "ZmazaÅ¥ oznaÄené kľúÄ(e)"
#: editor/animation_bezier_editor.cpp
msgid "Add Bezier Point"
-msgstr "Pridať Bezierov bod"
+msgstr "Pridať Bezier bod"
#: editor/animation_bezier_editor.cpp
msgid "Move Bezier Points"
@@ -191,7 +191,7 @@ msgstr "Zmeniť Dĺžku Animácie (Change Animation Length)"
#: editor/animation_track_editor.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Change Animation Loop"
-msgstr "Zmeniť opakovanie Animácie (Change Animation Loop)"
+msgstr "Zmeniť Opakovanie Animácie"
#: editor/animation_track_editor.cpp
msgid "Property Track"
@@ -256,7 +256,7 @@ msgstr "Zapnúť/Vypnúť tento track."
#: editor/animation_track_editor.cpp
msgid "Update Mode (How this property is set)"
-msgstr "Update Mode (ako je nastavená táto možnosť)"
+msgstr "Update Mode (Tak ako je táto možnosť nastavená)"
#: editor/animation_track_editor.cpp
msgid "Interpolation Mode"
@@ -517,7 +517,7 @@ msgstr "Zoskupte track-y pomocou node-u alebo ich zobrazte ako plain list."
#: editor/animation_track_editor.cpp
msgid "Snap:"
-msgstr "Snap:"
+msgstr "Prichytiť:"
#: editor/animation_track_editor.cpp
msgid "Animation step value."
@@ -756,9 +756,8 @@ msgid "Method in target node must be specified."
msgstr "Metóda v target node-e musí byť špecifikovaná."
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Method name must be a valid identifier."
-msgstr "Metóda v target node-e musí byť špecifikovaná."
+msgstr "Meno Metódy musí byť špecifikované."
#: editor/connections_dialog.cpp
msgid ""
@@ -1136,6 +1135,16 @@ msgid "Gold Sponsors"
msgstr "Zlatý Sponzori"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Strieborný Darcovia"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Bronzový Darcovia"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Malý Sponzori"
@@ -1886,7 +1895,7 @@ msgstr "PrieÄinky a Súbory:"
#: editor/plugins/style_box_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp
msgid "Preview:"
-msgstr "Ako to bude vyzerať:"
+msgstr "Predzobraziť:"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "File:"
@@ -2782,9 +2791,9 @@ msgid ""
msgstr ""
"KeÄ bude povolená táto možnosÅ¥, export alebo deploy vyprodukujú menej \n"
"súboru executable.\n"
-"Filesystém bude z projektu poskytovaný editorom v sieti. Na Androide, pre "
-"deploy budete potrebovať USB kábel \n"
-"rýchlejší výkon. Táto možnosť zrýchľuje proces testovania."
+"Filesystém bude z projektu poskytovaný editorom v sieti.\n"
+"Na Androide, predeploy budete potrebovať USB kábel pre rýchlejší výkon. Táto "
+"možnosť zrýchľuje proces testovania."
#: editor/editor_node.cpp
msgid "Visible Collision Shapes"
@@ -3053,19 +3062,19 @@ msgstr "Importovať Šablóny Zo ZIP File-u"
#: editor/editor_node.cpp
msgid "Template Package"
-msgstr "BalíÄek Å ablón"
+msgstr "Balík Šablón"
#: editor/editor_node.cpp
msgid "Export Library"
-msgstr "Exportovať Library"
+msgstr "Exportovať Knižnicu"
#: editor/editor_node.cpp
msgid "Merge With Existing"
-msgstr "Spojiť Z Existujúcim"
+msgstr "ZlúÄiÅ¥ s existujúcim"
#: editor/editor_node.cpp
msgid "Open & Run a Script"
-msgstr "Otvoriť & Spustiť Script"
+msgstr "Otvoriť a vykonať skript"
#: editor/editor_node.cpp
msgid "New Inherited"
@@ -3105,7 +3114,7 @@ msgstr "Otvoriť predchádzajúci Editor"
#: editor/editor_node.h
msgid "Warning!"
-msgstr "Varovanie!"
+msgstr "Upozornenie!"
#: editor/editor_path.cpp
msgid "No sub-resources found."
@@ -3113,7 +3122,7 @@ msgstr "Nenašli sa žiadne \"sub-resources\"."
#: editor/editor_plugin.cpp
msgid "Creating Mesh Previews"
-msgstr "Vytváranie Zobrazenia \"Mesh-u\""
+msgstr "Vytváranie Predzobrazenia Mesh-u"
#: editor/editor_plugin.cpp
msgid "Thumbnail..."
@@ -4223,7 +4232,7 @@ msgstr "Vyberte a premiestnite body, vytvorte body z RMB."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp scene/gui/graph_edit.cpp
msgid "Enable snap and show grid."
-msgstr "Povoliť snap a show grid."
+msgstr "Povoliť prichytenie a zobraziť mriežku."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4253,118 +4262,117 @@ msgstr "Pridať Trojuholník"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Change BlendSpace2D Limits"
-msgstr ""
+msgstr "Zmeniť Limity BlendSpace2D"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Change BlendSpace2D Labels"
-msgstr ""
+msgstr "Zmeniť Label BlendSpace2D"
#: editor/plugins/animation_blend_space_2d_editor.cpp
-#, fuzzy
msgid "Remove BlendSpace2D Point"
-msgstr "Všetky vybrané"
+msgstr "Vymazať BlendSpace2D Bod"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Remove BlendSpace2D Triangle"
-msgstr ""
+msgstr "Vymazať BlendSpace2D Trojuholník"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "BlendSpace2D does not belong to an AnimationTree node."
-msgstr ""
+msgstr "BlendSpace2D nepatrí ku AnimationTree node."
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "No triangles exist, so no blending can take place."
msgstr ""
+"Neexistujú žiadne trojuholníky, takže si nemôže zabrať miesto žiadny "
+"blending."
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Toggle Auto Triangles"
-msgstr ""
+msgstr "Prepnúť Automatické Trojuholníky"
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Create triangles by connecting points."
-msgstr ""
+msgstr "Vytvoriť trojuholníky spájaním bodov."
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Erase points and triangles."
-msgstr ""
+msgstr "Vymazať body a trojuholníky."
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Generate blend triangles automatically (instead of manually)"
-msgstr ""
+msgstr "Vygenerovať blend trojuholníky Automaticky (nie manuálne)"
#: editor/plugins/animation_blend_space_2d_editor.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Blend:"
-msgstr ""
+msgstr "Blend:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Parameter Changed"
-msgstr ""
+msgstr "Parameter sa Zmenil"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
-#, fuzzy
msgid "Edit Filters"
-msgstr "Súbor:"
+msgstr "Upraviť Filtre"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Output node can't be added to the blend tree."
-msgstr ""
+msgstr "Nemôžete pridať output node do blend tree."
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Add Node to BlendTree"
-msgstr ""
+msgstr "Pridať Node do BlendTree"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Node Moved"
-msgstr ""
+msgstr "Node sa pohol"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Unable to connect, port may be in use or connection may be invalid."
-msgstr ""
+msgstr "Nepodarilo sa pripojiť, port sa možno používa alebo je neplatný."
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Nodes Connected"
-msgstr ""
+msgstr "Node-y Spojené"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Nodes Disconnected"
-msgstr ""
+msgstr "Node-y Odpojené"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Set Animation"
-msgstr "Popis:"
+msgstr "Nastaviť Animáciu"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
-#, fuzzy
msgid "Delete Node"
-msgstr "Všetky vybrané"
+msgstr "Zmazať Node"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/scene_tree_dock.cpp
msgid "Delete Node(s)"
-msgstr ""
+msgstr "Zmazať Node(y)"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Toggle Filter On/Off"
-msgstr ""
+msgstr "Zapnúť/Vypnúť Filter"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Change Filter"
-msgstr ""
+msgstr "Zmeniť Filter"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "No animation player set, so unable to retrieve track names."
msgstr ""
+"Nieje nastavený AnimaÄný PrehrávaÄ, takže sa nepodarilo získaÅ¥ mená trackov."
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Player path set is invalid, so unable to retrieve track names."
-msgstr ""
+msgstr "Cesta prehrávaÄa je neplatná, takže sa nepodarilo získaÅ¥ mená trackov."
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/root_motion_editor_plugin.cpp
@@ -4372,312 +4380,302 @@ msgid ""
"Animation player has no valid root node path, so unable to retrieve track "
"names."
msgstr ""
+"AnimaÄný PrehrávaÄ nemá žiadny platnú root node cestu, takže sa nepodarilo "
+"zistiť mená trackov."
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Anim Clips"
-msgstr "Klipy Animácie:"
+msgstr "Klipy Animácie"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Audio Clips"
-msgstr "Zvukové Klipy:"
+msgstr "Zvukové Klipy"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
-#, fuzzy
msgid "Functions"
-msgstr "Funkcie:"
+msgstr "Funkcie"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Node Renamed"
-msgstr ""
+msgstr "Node Premenovaný"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Add Node..."
-msgstr ""
+msgstr "Pridať Node..."
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
#: editor/plugins/root_motion_editor_plugin.cpp
-#, fuzzy
msgid "Edit Filtered Tracks:"
-msgstr "Súbor:"
+msgstr "Upraviť Filtrované Tracky:"
#: editor/plugins/animation_blend_tree_editor_plugin.cpp
msgid "Enable Filtering"
-msgstr ""
+msgstr "Povoliť Filtrovanie"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Toggle Autoplay"
-msgstr ""
+msgstr "Prepnúť Autoplay"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "New Animation Name:"
-msgstr ""
+msgstr "Nové Meno Animácie:"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "New Anim"
-msgstr ""
+msgstr "Nová Animácia"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Change Animation Name:"
-msgstr ""
+msgstr "Zmeniť Meno Animácie:"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Delete Animation?"
-msgstr ""
+msgstr "Naozaj chcete vymazať Animáciu?"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Remove Animation"
-msgstr ""
+msgstr "Vymazať Animáciu"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Invalid animation name!"
-msgstr ""
+msgstr "Meno animácie je Vadné!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation name already exists!"
-msgstr ""
+msgstr "Toto meno Animácie už existuje!"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Rename Animation"
-msgstr ""
+msgstr "Premenovať Animáciu"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Blend Next Changed"
-msgstr ""
+msgstr "Blend sa ÄŽalej Zmenil"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Change Blend Time"
-msgstr ""
+msgstr "Zmeniť Blend Time"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Load Animation"
-msgstr ""
+msgstr "NaÄítaÅ¥ Animáciu"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Duplicate Animation"
-msgstr ""
+msgstr "Duplikovať Animáciu"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "No animation to copy!"
-msgstr ""
+msgstr "Žiadne animácie na skopírovanie!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "No animation resource on clipboard!"
-msgstr ""
+msgstr "Žiadny zroj animácie v clipboard!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Pasted Animation"
-msgstr ""
+msgstr "Prilepená Animácia"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Paste Animation"
-msgstr ""
+msgstr "Prilepiť Animáciu"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "No animation to edit!"
-msgstr ""
+msgstr "Žiadna animácia na úpravu!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Play selected animation backwards from current pos. (A)"
-msgstr ""
+msgstr "Spusťiť vybranú animáciu odzadu z aktuálnej pozície. (A)"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Play selected animation backwards from end. (Shift+A)"
-msgstr ""
+msgstr "Spustiť vybranú animáciu odzadu z konca. (Shift+A)"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Stop animation playback. (S)"
-msgstr ""
+msgstr "Zastaviť playback animácie. (S)"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Play selected animation from start. (Shift+D)"
-msgstr ""
+msgstr "SpustiÅ¥ vybranú animáciu od zaÄiatku. (Shift+D)"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Play selected animation from current pos. (D)"
-msgstr ""
+msgstr "Spustiť vybranú animáciu z aktuálnej pozície. (D)"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation position (in seconds)."
-msgstr ""
+msgstr "Pozícia Animácie (v sekundách)."
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Scale animation playback globally for the node."
-msgstr ""
+msgstr "ZväÄÅ¡iÅ¥ playback animácie globálne pre node."
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation Tools"
-msgstr ""
+msgstr "AnimaÄné Náradie"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation"
msgstr "Animácie"
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "Edit Transitions..."
-msgstr "Prechody"
+msgstr "Upraviť Prechody..."
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "Open in Inspector"
-msgstr "Otvorit prieÄinok"
+msgstr "Otvorit v Inšpektor-ovi"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Display list of animations in player."
-msgstr ""
+msgstr "ZobraziÅ¥ list animácii v prehrávaÄi."
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Autoplay on Load"
-msgstr ""
+msgstr "Autoplay pri NaÄítaní"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Enable Onion Skinning"
-msgstr ""
+msgstr "Povoliť Onion Skinning"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Onion Skinning Options"
-msgstr ""
+msgstr "Onion Skinning Možnosti"
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "Directions"
-msgstr "Popis:"
+msgstr "Smery"
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "Past"
-msgstr "Vložiť"
+msgstr "Minulosť"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Future"
-msgstr ""
+msgstr "Budúcnosť"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Depth"
-msgstr ""
+msgstr "Hĺbka"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "1 step"
-msgstr ""
+msgstr "1 krok"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "2 steps"
-msgstr ""
+msgstr "2 kroky"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "3 steps"
-msgstr ""
+msgstr "3 kroky"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Differences Only"
-msgstr ""
+msgstr "Iba Odlišnosti"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Force White Modulate"
-msgstr ""
+msgstr "Force White Modulate"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Include Gizmos (3D)"
-msgstr ""
+msgstr "Zahŕňa Gizmos (3D)"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Pin AnimationPlayer"
-msgstr ""
+msgstr "Pripnúť PrehrávaÄ Animácie"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Create New Animation"
-msgstr ""
+msgstr "Vytvoriť Novú Animáciu"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Animation Name:"
-msgstr ""
+msgstr "Meno Animácie:"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/resource_preloader_editor_plugin.cpp
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp
msgid "Error!"
-msgstr ""
+msgstr "Chyba!"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Blend Times:"
-msgstr ""
+msgstr "Blend Times:"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Next (Auto Queue):"
-msgstr ""
+msgstr "Ďalej (Automatický Rad):"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Cross-Animation Blend Times"
-msgstr ""
+msgstr "Cross-Animation Blend Times"
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Move Node"
-msgstr "Vložiť"
+msgstr "Premiestniť Node"
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Transition exists!"
-msgstr "Prechody"
+msgstr "Prechod existuje!"
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Add Transition"
-msgstr "Prechody"
+msgstr "Pridať Prechod"
#: editor/plugins/animation_state_machine_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Node"
-msgstr ""
+msgstr "Pridať Node"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "End"
-msgstr ""
+msgstr "Koniec"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Immediate"
-msgstr ""
+msgstr "Okamžite"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Sync"
-msgstr ""
+msgstr "Synchronizácia"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "At End"
-msgstr ""
+msgstr "Na Konci"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Travel"
-msgstr ""
+msgstr "Cestovať"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Start and end nodes are needed for a sub-transition."
-msgstr ""
+msgstr "Pre sub-prechod je potrebné zaÄaÅ¥ a skonÄiÅ¥ node-y."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "No playback resource set at path: %s."
-msgstr ""
+msgstr "Nieje nastavený žiadny zdrojový playback ako cesta: %s."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Node Removed"
-msgstr ""
+msgstr "Node Zmazaný"
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Transition Removed"
-msgstr "Prechody"
+msgstr "Prechod Vymazaný"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Set Start Node (Autoplay)"
-msgstr ""
+msgstr "NastaviÅ¥ ZaÄiatoÄný Node (Autoplay)"
#: editor/plugins/animation_state_machine_editor.cpp
msgid ""
@@ -4685,363 +4683,356 @@ msgid ""
"RMB to add new nodes.\n"
"Shift+LMB to create connections."
msgstr ""
+"Vybrať a premiestniť node-y.\n"
+"Pravím tlaÄítkom myÅ¡i pridáte node-y.\n"
+"Shift+Lavé tlaÄíko myÅ¡i vytvoriÅ¥ pripojenie."
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Create new nodes."
-msgstr "Vytvoriť adresár"
+msgstr "Vytvoriť Nové Node-y."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Connect nodes."
-msgstr ""
+msgstr "Spojiť Node-y."
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Remove selected node or transition."
-msgstr "Odstrániť výber"
+msgstr "VymazaÅ¥ oznaÄený node alebo prechod."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Toggle autoplay this animation on start, restart or seek to zero."
msgstr ""
+"Prepnúť autoplay na tejto animácii pri štarte, reštarte alebo seek to zero."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Set the end animation. This is useful for sub-transitions."
-msgstr ""
+msgstr "NastaviÅ¥ koniec animácie. Toto je užitoÄné pre sub-prechody."
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Transition: "
-msgstr "Prechody"
+msgstr "Prechody: "
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Play Mode:"
-msgstr "Cesta k Node:"
+msgstr "Prehrať Mód:"
#: editor/plugins/animation_tree_editor_plugin.cpp
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "AnimationTree"
-msgstr ""
+msgstr "AnimaÄnýStrom"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "New name:"
-msgstr ""
+msgstr "Nové Meno:"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Scale:"
-msgstr ""
+msgstr "Veľkosť:"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Fade In (s):"
-msgstr ""
+msgstr "Miznutie do (s):"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Fade Out (s):"
-msgstr ""
+msgstr "Miznutie Von (s):"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Blend"
-msgstr ""
+msgstr "Blend"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Mix"
-msgstr ""
+msgstr "Mix"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Auto Restart:"
-msgstr ""
+msgstr "Auto Reštart:"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Restart (s):"
-msgstr ""
+msgstr "Reštart (s):"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Random Restart (s):"
-msgstr ""
+msgstr "Náhodný Reštart (s):"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Start!"
-msgstr ""
+msgstr "Å tart!"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "Amount:"
-msgstr ""
+msgstr "Množstvo:"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Blend 0:"
-msgstr ""
+msgstr "Blend 0:"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Blend 1:"
-msgstr ""
+msgstr "Blend 1:"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "X-Fade Time (s):"
-msgstr ""
+msgstr "ÄŒas X-Miznutia (s):"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Current:"
-msgstr ""
+msgstr "Aktuálny:"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Input"
-msgstr ""
+msgstr "Pridať Vstup"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Clear Auto-Advance"
-msgstr ""
+msgstr "Čistý Auto-Advance"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Set Auto-Advance"
-msgstr ""
+msgstr "Nastaviť Auto-Advance"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Delete Input"
-msgstr ""
+msgstr "Zmazať Vstup"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Animation tree is valid."
-msgstr ""
+msgstr "AnimaÄný Strom je platný."
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Animation tree is invalid."
-msgstr ""
+msgstr "AnimaÄný Strom je neplatný."
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Animation Node"
-msgstr ""
+msgstr "AnimaÄný Node"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "OneShot Node"
-msgstr ""
+msgstr "OneShot Node"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Mix Node"
-msgstr ""
+msgstr "Mix Node"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Blend2 Node"
-msgstr ""
+msgstr "Blend2 Node"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Blend3 Node"
-msgstr ""
+msgstr "Blend3 Node"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Blend4 Node"
-msgstr ""
+msgstr "Blend4 Node"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "TimeScale Node"
-msgstr ""
+msgstr "TimeScale Node"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "TimeSeek Node"
-msgstr ""
+msgstr "TimeSeek Node"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Transition Node"
-msgstr ""
+msgstr "Prechodový Node"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Import Animations..."
-msgstr ""
+msgstr "Importovať Animácie..."
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Edit Node Filters"
-msgstr ""
+msgstr "Nastaviť Node Filtre"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "Filters..."
-msgstr ""
+msgstr "Filtre..."
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Contents:"
-msgstr "Konštanty:"
+msgstr "Obsah:"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "View Files"
-msgstr "Súbor:"
+msgstr "Zobraziť Súbory"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Connection error, please try again."
-msgstr ""
+msgstr "Chyba pripojenia, prosím skúste znovu."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Can't connect to host:"
-msgstr ""
+msgstr "Nepodarilo sa pripojiť k host:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "No response from host:"
-msgstr ""
+msgstr "Žiadna odozva od host-a:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Can't resolve hostname:"
-msgstr ""
+msgstr "Nepodarilo sa rozlúštiť hostove meno:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Request failed, return code:"
-msgstr ""
+msgstr "Žiadosť zlyhala, spätný kód:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Request failed."
-msgstr ""
+msgstr "Žiadosť zlyhala."
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Cannot save response to:"
-msgstr "Nemôžete odstrániť:"
+msgstr "Nepodarilo sa uložiÅ¥ odpoveÄ do:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Write error."
-msgstr ""
+msgstr "Chyba písania."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Request failed, too many redirects"
-msgstr ""
+msgstr "Žiadosť zlyhala, príliš veľa presmerovaní"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Redirect loop."
-msgstr ""
+msgstr "Presmerovací loop."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Request failed, timeout"
-msgstr ""
+msgstr "ŽiadosÅ¥ zlyhala, Äas vyprÅ¡al"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Timeout."
-msgstr "ÄŒas:"
+msgstr "Čas vypršal."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Bad download hash, assuming file has been tampered with."
-msgstr ""
+msgstr "Zlý download hash, za predpokladu že bolo narábané so súborom."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Expected:"
-msgstr ""
+msgstr "OÄakávané:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Got:"
-msgstr ""
+msgstr "Má:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Failed sha256 hash check"
-msgstr ""
+msgstr "Zlyhalo sha256 hash check"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Asset Download Error:"
-msgstr ""
+msgstr "Zlyhalo SÅ¥ahovanie Prostriedku:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Downloading (%s / %s)..."
-msgstr ""
+msgstr "SÅ¥ahovanie (%s / %s)..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Downloading..."
-msgstr ""
+msgstr "SÅ¥ahovanie..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Resolving..."
-msgstr ""
+msgstr "Rieši sa..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Error making request"
-msgstr ""
+msgstr "Pri vytváraní žiadosťi nastala chyba"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Idle"
-msgstr ""
+msgstr "Idle"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Install..."
-msgstr "Inštalovať"
+msgstr "Inštalovať..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Retry"
-msgstr ""
+msgstr "Skúsiť znova"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Download Error"
-msgstr ""
+msgstr "Chyba SÅ¥ahovania"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Download for this asset is already in progress!"
-msgstr ""
+msgstr "Sťahovanie tohoto prostriedku už prebieha!"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Recently Updated"
-msgstr ""
+msgstr "Nedávno Vylepšené"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Least Recently Updated"
-msgstr ""
+msgstr "Za Poslednú Dobu Najmenej Aktualizované"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Name (A-Z)"
-msgstr ""
+msgstr "Meno (A-Z)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Name (Z-A)"
-msgstr ""
+msgstr "Meno (Z-A)"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "License (A-Z)"
-msgstr "Licencia"
+msgstr "Licencia (A-Z)"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "License (Z-A)"
-msgstr "Licencia"
+msgstr "Licencia (Z-A)"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "First"
-msgstr ""
+msgstr "Prvý"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Previous"
-msgstr ""
+msgstr "Minulý"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Next"
-msgstr ""
+msgstr "Ďalší"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Last"
-msgstr ""
+msgstr "Posledný"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "All"
-msgstr ""
+msgstr "Všetky"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "No results for \"%s\"."
-msgstr ""
+msgstr "Žiadne výsledky pre \"%s\"."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Import..."
-msgstr ""
+msgstr "Import..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Plugins..."
-msgstr ""
+msgstr "Pluginy..."
#: editor/plugins/asset_library_editor_plugin.cpp editor/project_manager.cpp
msgid "Sort:"
-msgstr ""
+msgstr "Zoradiť:"
#: editor/plugins/asset_library_editor_plugin.cpp
#: editor/project_settings_editor.cpp
msgid "Category:"
-msgstr ""
+msgstr "Kategória:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Site:"
@@ -5049,23 +5040,23 @@ msgstr "Stránka:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Support"
-msgstr ""
+msgstr "Podpora"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Official"
-msgstr ""
+msgstr "Oficiálne"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Testing"
-msgstr ""
+msgstr "Testovanie"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Loading..."
-msgstr ""
+msgstr "NaÄitávanie..."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Assets ZIP File"
-msgstr ""
+msgstr "Prostriedky Súboru ZIP"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
@@ -5073,216 +5064,215 @@ msgid ""
"Save your scene (for images to be saved in the same dir), or pick a save "
"path from the BakedLightmap properties."
msgstr ""
+"Nedá sa urÄiÅ¥ cesta pre uloženie lightmap obrázkov.\n"
+"Uložte svoju scénu (Aby sa obrázky na to isté miesto), alebo vyberte cestu "
+"na uloženie so BakedLightmap vlastností."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid ""
"No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake "
"Light' flag is on."
msgstr ""
+"Žiadne mesh-e na bake. Uistite sa že obsahujú UV2 channel a je na ňom 'Bake "
+"Light' vlajka."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Failed creating lightmap images, make sure path is writable."
msgstr ""
+"Nepodarilo sa vytvoriÅ¥ lightmap obrázok, uistite sa že Äi je cesta "
+"zapisovateľná."
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Bake Lightmaps"
-msgstr ""
+msgstr "Bake Lightmaps"
#: editor/plugins/camera_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp editor/rename_dialog.cpp
msgid "Preview"
-msgstr ""
+msgstr "Predzobraziť"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Configure Snap"
-msgstr ""
+msgstr "Konfigurovať Prichytenie"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Offset:"
-msgstr ""
+msgstr "Odchýlka Mriežky:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Grid Step:"
-msgstr ""
+msgstr "Krok Mriežky:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Primary Line Every:"
-msgstr ""
+msgstr "Všetky Primary Line:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "steps"
-msgstr ""
+msgstr "kroky"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation Offset:"
-msgstr ""
+msgstr "Odchýlka Rotácie:"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation Step:"
-msgstr ""
+msgstr "Krok Rotácie:"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Scale Step:"
-msgstr "Zmeniť veľkosť výberu"
+msgstr "Krok Veľkosti:"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move Vertical Guide"
-msgstr "Popis:"
+msgstr "Presunúť Vertikálny Návod"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Create Vertical Guide"
-msgstr "Popis:"
+msgstr "Vytvoriť Vertikálny Návod"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Remove Vertical Guide"
-msgstr "Všetky vybrané"
+msgstr "Vymazať Vertikálny Návod"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move Horizontal Guide"
-msgstr "Všetky vybrané"
+msgstr "Presunúť Horizontálny Návod"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Create Horizontal Guide"
-msgstr "Popis:"
+msgstr "Vytvoriť Horizontálny Návod"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Remove Horizontal Guide"
-msgstr "Všetky vybrané"
+msgstr "Vymazať Horizontálny Návod"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Create Horizontal and Vertical Guides"
-msgstr "Popis:"
+msgstr "Vytvoriť Horizontálne a Vertikálne Návody"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Move pivot"
-msgstr "Všetky vybrané"
+msgstr "Presunúť pivot"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotate CanvasItem"
-msgstr ""
+msgstr "OtoÄiÅ¥ CanvasItem"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Move anchor"
-msgstr ""
+msgstr "Presunúť kovadlinu"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Resize CanvasItem"
-msgstr ""
+msgstr "Zmeniť Veľkosť CanvasItem-u"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale CanvasItem"
-msgstr ""
+msgstr "Veľkosť CanvasItem-u"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Move CanvasItem"
-msgstr ""
+msgstr "Presunúť CanvasItem"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
"Children of containers have their anchors and margins values overridden by "
"their parent."
msgstr ""
+"DieÅ¥a kontajnerov majú svoje kovadliny a okraje prepísané svojimi rodiÄmi."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Presets for the anchors and margins values of a Control node."
-msgstr ""
+msgstr "Prenastaviť pre kovadliny a okraje hodnoty Control node-u."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
"When active, moving Control nodes changes their anchors instead of their "
"margins."
msgstr ""
+"Pri aktivovaní, pohybovanim Control node-ov zmeníte ich kovadliny namiesto "
+"ich okrajov."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Top Left"
-msgstr ""
+msgstr "Vľavo Hore"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Top Right"
-msgstr ""
+msgstr "Vpravo Hore"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Bottom Right"
-msgstr ""
+msgstr "Vpravo Dole"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Bottom Left"
-msgstr ""
+msgstr "Vľavo Dole"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Left"
-msgstr ""
+msgstr "Od Stredu Vľavo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Top"
-msgstr ""
+msgstr "Od Stredu Hore"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Right"
-msgstr ""
+msgstr "Od Stredu Vpravo"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Bottom"
-msgstr ""
+msgstr "Od Stredu Dole"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center"
-msgstr ""
+msgstr "V Strede"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Left Wide"
-msgstr "Lineárne"
+msgstr "Ľavá Šírka"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Top Wide"
-msgstr ""
+msgstr "Horná Šírka"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Right Wide"
-msgstr "Lineárne"
+msgstr "Pravá Šírka"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Bottom Wide"
-msgstr ""
+msgstr "Dolná Šírka"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "VCenter Wide"
-msgstr ""
+msgstr "VerStredná Šírka"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "HCenter Wide"
-msgstr ""
+msgstr "HorStredná Šírka"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Full Rect"
-msgstr ""
+msgstr "Plný Obdĺžnik"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Keep Ratio"
-msgstr ""
+msgstr "Udržovať Pomer"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Anchors only"
-msgstr ""
+msgstr "Iba Kovadliny"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Change Anchors and Margins"
-msgstr ""
+msgstr "Zmeniť Kovadliny a Okraje"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Change Anchors"
-msgstr ""
+msgstr "Zmeniť Kovadliny"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5290,6 +5280,8 @@ msgid ""
"Game Camera Override\n"
"Overrides game camera with editor viewport camera."
msgstr ""
+"Prepísanie Hernej Kamery\n"
+"Prepísať hernú kameru s viewport kamerou editora."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5297,104 +5289,103 @@ msgid ""
"Game Camera Override\n"
"No game instance running."
msgstr ""
+"Prepísanie Hernej Kamery\n"
+"Nieje spustená žiadna herná inštancia."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Lock Selected"
-msgstr "Všetky vybrané"
+msgstr "Zamknúť OznaÄené"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Unlock Selected"
-msgstr "Všetky vybrané"
+msgstr "Odomknúť OznaÄené"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Group Selected"
-msgstr "Odstrániť výber"
+msgstr "PridaÅ¥ OznaÄené do Skupiny"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Ungroup Selected"
-msgstr "Odstrániť výber"
+msgstr "OdskupiÅ¥ OznaÄené"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Paste Pose"
-msgstr ""
+msgstr "Prilepiť Pózu"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Clear Guides"
-msgstr "Všetky vybrané"
+msgstr "Zmazať Návody"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Create Custom Bone(s) from Node(s)"
-msgstr ""
+msgstr "Vytvoriť Vlastnú Kosť(i) z Node-u(ou)"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Clear Bones"
-msgstr "Všetky vybrané"
+msgstr "Zmazať Kosti"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Make IK Chain"
-msgstr ""
+msgstr "Vytvoriť IK Reťaz"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear IK Chain"
-msgstr ""
+msgstr "Zmazať IK Reťaz"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
"Warning: Children of a container get their position and size determined only "
"by their parent."
msgstr ""
+"Upozornenie: Dieťa kontajnera získa ich pozíciu a veľkosť iba podľa svojho "
+"rodiÄa."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/texture_region_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
msgid "Zoom Reset"
-msgstr ""
+msgstr "Resetovať Priblíženie"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Select Mode"
-msgstr ""
+msgstr "Vybrať Režim"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Drag: Rotate"
-msgstr ""
+msgstr "Potiahnutím: OtáÄenie"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Alt+Drag: Move"
-msgstr ""
+msgstr "Alt+Potiahnutie: Pohyb"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Press 'v' to Change Pivot, 'Shift+v' to Drag Pivot (while moving)."
msgstr ""
+"StaÄte 'v' pre Zmenu Pivot-a, 'Shift+v' pre hýbanie s Pivot-om (keÄ sa hýbe)."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Alt+RMB: Depth list selection"
-msgstr ""
+msgstr "Alt+RMB: Výber hĺbkového zoznamu"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Move Mode"
-msgstr ""
+msgstr "Move Mode"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotate Mode"
-msgstr ""
+msgstr "RotaÄný Režim"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scale Mode"
-msgstr ""
+msgstr "Zmena Veľkosti"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5402,187 +5393,186 @@ msgid ""
"Show a list of all objects at the position clicked\n"
"(same as Alt+RMB in select mode)."
msgstr ""
+"Zobraziť list všetkých objektov na kliknutej pozícii\n"
+"(rovnako ako Alt+RMB v výberovom režime)."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Click to change object's rotation pivot."
-msgstr ""
+msgstr "Kliknite pre zmenu rotaÄného pivota objektu."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Pan Mode"
-msgstr ""
+msgstr "Pohyb Mód"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Ruler Mode"
-msgstr "Režim Interpolácie"
+msgstr "Pravítko"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Toggle smart snapping."
-msgstr ""
+msgstr "Prepnúť smart prichytenie."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Smart Snap"
-msgstr ""
+msgstr "Použiť Smart Prichytenie"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Toggle grid snapping."
-msgstr ""
+msgstr "Prepnúť Prichytenie Mriežky."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Grid Snap"
-msgstr ""
+msgstr "Použiť Príchyt Mriežky"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snapping Options"
-msgstr ""
+msgstr "Možnosti Prichytávania"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Rotation Snap"
-msgstr ""
+msgstr "Použiť Prichytávanie Rotácie"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Scale Snap"
-msgstr ""
+msgstr "Použiť Prichytávanie Veľkosti"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap Relative"
-msgstr ""
+msgstr "Prichytiť Relatívne"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Use Pixel Snap"
-msgstr ""
+msgstr "Použiť Pixelové Prichytenie"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Smart Snapping"
-msgstr ""
+msgstr "Smart Prichytávanie"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Configure Snap..."
-msgstr ""
+msgstr "Konfigurovať Prichytávanie..."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Parent"
-msgstr ""
+msgstr "PrichytiÅ¥ na RodiÄa"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Node Anchor"
-msgstr ""
+msgstr "Prichytiť na Kovadlinu Node-u"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Node Sides"
-msgstr ""
+msgstr "Prichitiť na strany Node-u"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Node Center"
-msgstr ""
+msgstr "Prichytiť na Stred Node-u"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Snap to Other Nodes"
-msgstr "Vložiť"
+msgstr "Prichytiť na Ostatné Node-y"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap to Guides"
-msgstr ""
+msgstr "Prichytiť na Návody"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Lock the selected object in place (can't be moved)."
-msgstr ""
+msgstr "Zamknúť oznaÄený objekt na mieste (už sa s ním nebude daÅ¥ hýbaÅ¥)."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Unlock the selected object (can be moved)."
-msgstr ""
+msgstr "Odomknúť oznaÄený objekt (dá sa s ním hýbaÅ¥)."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Makes sure the object's children are not selectable."
-msgstr ""
+msgstr "Uistite sa že sa nedá oznaÄiÅ¥ dieÅ¥a objektu."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Restores the object's children's ability to be selected."
-msgstr ""
+msgstr "Aby ste oznaÄili dieÅ¥a objektu tak mu musíte obnoviÅ¥ schopnosÅ¥."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Skeleton Options"
-msgstr "Všetky vybrané"
+msgstr "Nastavenia Kostry"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Bones"
-msgstr ""
+msgstr "Zobraziť Kosti"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Make Custom Bone(s) from Node(s)"
-msgstr ""
+msgstr "Vytvoriť Vlastnú Kosť(i) z Node-u(ou)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear Custom Bones"
-msgstr ""
+msgstr "Zmazať Vlastné Kosti"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View"
-msgstr ""
+msgstr "Zobrazenie"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Always Show Grid"
-msgstr ""
+msgstr "Vždy Zobraziť Mriežku"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Helpers"
-msgstr ""
+msgstr "Zobraziť Pomocníkov"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Rulers"
-msgstr ""
+msgstr "Zobraziť Pravítka"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Guides"
-msgstr ""
+msgstr "Zobraziť Návody"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Origin"
-msgstr ""
+msgstr "Zobraziť Pôvod"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Viewport"
-msgstr ""
+msgstr "Zobraziť Výrez"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Group And Lock Icons"
-msgstr ""
+msgstr "Zobraziť Skupinu a Zamknúť Ikony"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Selection"
-msgstr ""
+msgstr "Výber Stredu"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Frame Selection"
-msgstr ""
+msgstr "Výber Frame-u"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Preview Canvas Scale"
-msgstr ""
+msgstr "Predzobraziť Veľkosť Plátna"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Translation mask for inserting keys."
-msgstr ""
+msgstr "Prekladová maska na vkladanie kľúÄov."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation mask for inserting keys."
-msgstr ""
+msgstr "RotaÄná maska na vkladanie kľúÄov."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale mask for inserting keys."
-msgstr ""
+msgstr "Veľkostná maska na vkladanie kľúÄov."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Insert keys (based on mask)."
-msgstr ""
+msgstr "Vkladanie kľúÄov (založené na maske)."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
@@ -5591,67 +5581,69 @@ msgid ""
"Keys are only added to existing tracks, no new tracks will be created.\n"
"Keys must be inserted manually for the first time."
msgstr ""
+"Automaticky vložiÅ¥ kľúÄe keÄ sú objekty preložené, rotované alebo zväÄÅ¡ené "
+"(založené na maske).\n"
+"KľúÄe sú pridané iba do existujúcich track-ov, nebudú vytvorené žiadne nové "
+"tracky.\n"
+"Prvý krát musia byÅ¥ kľúÄe vložené manuálne."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Auto Insert Key"
-msgstr "Animácia VložiÅ¥ KľúÄ"
+msgstr "Automaticky VložiÅ¥ KľúÄ"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Animation Key and Pose Options"
-msgstr "Dĺžka Času Animácie (v sekundách)"
+msgstr "AnimaÄný KÄ¾ÃºÄ a Možnosti Pozície"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Insert Key (Existing Tracks)"
-msgstr ""
+msgstr "Vložte KÄ¾ÃºÄ (Existujúce Tracky)"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Copy Pose"
-msgstr ""
+msgstr "Kopírovať Pozíciu"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear Pose"
-msgstr ""
+msgstr "Zmazať Pozíciu"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Multiply grid step by 2"
-msgstr ""
+msgstr "Zdvojnásobiť krok mriežky dvomi"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Divide grid step by 2"
-msgstr ""
+msgstr "vydeliť krok mriežky dvomi"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Pan View"
-msgstr ""
+msgstr "Zobrazenie Pan"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Add %s"
-msgstr ""
+msgstr "Pridať %s"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Adding %s..."
-msgstr ""
+msgstr "Pridávanie %s..."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Cannot instantiate multiple nodes without root."
-msgstr ""
+msgstr "Nie je možné vytvoriť inštanciu viacerých node-ov bez koreňa."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "Create Node"
-msgstr ""
+msgstr "Vytvoriť Node"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "Error instancing scene from %s"
-msgstr ""
+msgstr "Chyba pri inštalácovaní scény z %s"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Change Default Type"
-msgstr "Zmeniť %s Typ"
+msgstr "Zmeniť Predvolený Typ"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
@@ -5660,9 +5652,8 @@ msgid ""
msgstr ""
#: editor/plugins/collision_polygon_editor_plugin.cpp
-#, fuzzy
msgid "Create Polygon3D"
-msgstr "Vytvoriť adresár"
+msgstr "Vytvoriť Polygon3D"
#: editor/plugins/collision_polygon_editor_plugin.cpp
msgid "Edit Poly"
@@ -6529,11 +6520,11 @@ msgstr ""
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Snap"
-msgstr ""
+msgstr "Prichytiť"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Enable Snap"
-msgstr ""
+msgstr "Povoliť Prichytávanie"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Grid"
@@ -7356,7 +7347,7 @@ msgstr "Filter:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Cinematic Preview"
-msgstr ""
+msgstr "Filmové Predzobrazenie"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Not available when using the GLES2 renderer."
@@ -7419,11 +7410,11 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Nodes To Floor"
-msgstr ""
+msgstr "Prichytiť Node-y Na Zem"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Couldn't find a solid floor to snap the selection to."
-msgstr ""
+msgstr "Nepodarilo sa nájsť pevnú zem na prichytenie výberu."
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
@@ -7438,7 +7429,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Use Snap"
-msgstr ""
+msgstr "Použiť Prichytávanie"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Bottom View"
@@ -7492,7 +7483,7 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Object to Floor"
-msgstr ""
+msgstr "Prichytiť Objekt na Zem"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Transform Dialog..."
@@ -7541,19 +7532,19 @@ msgstr ""
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Settings"
-msgstr ""
+msgstr "Nastavenie Prichytenia"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Translate Snap:"
-msgstr ""
+msgstr "Preložiť Preloženie:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotate Snap (deg.):"
-msgstr ""
+msgstr "Prichytenie Rotácie (v stupňoch.):"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Scale Snap (%):"
-msgstr ""
+msgstr "Prichytenie Veľkosti (%):"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Viewport Settings"
@@ -7610,7 +7601,7 @@ msgstr "Vytvoriť adresár"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Mesh2D Preview"
-msgstr ""
+msgstr "Predzobraziť Mash2D"
#: editor/plugins/sprite_editor_plugin.cpp
#, fuzzy
@@ -7619,7 +7610,7 @@ msgstr "Vytvoriť adresár"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Polygon2D Preview"
-msgstr ""
+msgstr "Predzobraziť Polygon2D"
#: editor/plugins/sprite_editor_plugin.cpp
#, fuzzy
@@ -7627,9 +7618,8 @@ msgid "Create CollisionPolygon2D"
msgstr "Vytvoriť adresár"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "CollisionPolygon2D Preview"
-msgstr "Vytvoriť adresár"
+msgstr "Predzobraziť CollisionPolygon2D"
#: editor/plugins/sprite_editor_plugin.cpp
#, fuzzy
@@ -7637,9 +7627,8 @@ msgid "Create LightOccluder2D"
msgstr "Vytvoriť adresár"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "LightOccluder2D Preview"
-msgstr "Vytvoriť adresár"
+msgstr "Predzobraziť LightOccluder2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Sprite is empty!"
@@ -7701,7 +7690,7 @@ msgstr ""
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Update Preview"
-msgstr ""
+msgstr "Predzobraziť Vylepšenie"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Settings:"
@@ -7835,7 +7824,7 @@ msgstr ""
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Snap Mode:"
-msgstr ""
+msgstr "Režim Prichytenia:"
#: editor/plugins/texture_region_editor_plugin.cpp
#: scene/resources/visual_shader.cpp
@@ -7844,11 +7833,11 @@ msgstr ""
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Pixel Snap"
-msgstr ""
+msgstr "Prichytenie Pixelov"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Grid Snap"
-msgstr ""
+msgstr "Prichytenie Mriežky"
#: editor/plugins/texture_region_editor_plugin.cpp
msgid "Auto Slice"
@@ -8274,6 +8263,7 @@ msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Enable snap and show grid (configurable via the Inspector)."
msgstr ""
+"Povoliť prichytávanie a zobraziť mriežku (konfigurovatelné cez inšpektor)."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Display Tile Names (Hold Alt Key)"
@@ -8322,11 +8312,12 @@ msgid "Delete selected Rect."
msgstr "Všetky vybrané"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid ""
"Select current edited sub-tile.\n"
"Click on another Tile to edit it."
-msgstr "Vytvoriť adresár"
+msgstr ""
+"Vybrať aktuálne upravený pod-nadpis.\n"
+"Kliknite na Äalší Nadpis aby ste ho upravili."
#: editor/plugins/tile_set_editor_plugin.cpp
#, fuzzy
@@ -8334,13 +8325,16 @@ msgid "Delete polygon."
msgstr "Všetky vybrané"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid ""
"LMB: Set bit on.\n"
"RMB: Set bit off.\n"
"Shift+LMB: Set wildcard bit.\n"
"Click on another Tile to edit it."
-msgstr "Vytvoriť adresár"
+msgstr ""
+"LMB: Zapnúť bit.\n"
+"RMB: Vypnúť bit.\n"
+"Shift+LMB: Nastaviť wildcard bit.\n"
+"Kliknite na Äalší Nadpis pre úpravu."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid ""
@@ -8356,11 +8350,12 @@ msgid ""
msgstr ""
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid ""
"Select sub-tile to change its z index.\n"
"Click on another Tile to edit it."
-msgstr "Vytvoriť adresár"
+msgstr ""
+"Vybrať podnadpis aby ste zmenili jeho index.\n"
+"Kliknite na Äalší Nadpis na úpravu."
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Set Tile Region"
@@ -10488,14 +10483,12 @@ msgid "Make node as Root"
msgstr ""
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete %d nodes and any children?"
-msgstr "Všetky vybrané"
+msgstr "Zmazať %d node-y a nejaké deti?"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete %d nodes?"
-msgstr "Všetky vybrané"
+msgstr "Zmazať %d node-y?"
#: editor/scene_tree_dock.cpp
msgid "Delete the root node \"%s\"?"
@@ -10506,9 +10499,8 @@ msgid "Delete node \"%s\" and its children?"
msgstr ""
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete node \"%s\"?"
-msgstr "Všetky vybrané"
+msgstr "Zmazať node \"%s\"?"
#: editor/scene_tree_dock.cpp
msgid "Can not perform with the root node."
@@ -10711,9 +10703,8 @@ msgid "Button Group"
msgstr "TlaÄidlo"
#: editor/scene_tree_editor.cpp
-#, fuzzy
msgid "(Connecting From)"
-msgstr "Pripojiť Signál: "
+msgstr "(Pripájanie z)"
#: editor/scene_tree_editor.cpp
msgid "Node configuration warning:"
@@ -10917,9 +10908,8 @@ msgid "Attach Node Script"
msgstr "Popis:"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Remote "
-msgstr "Všetky vybrané"
+msgstr "Diaľkový "
#: editor/script_editor_debugger.cpp
msgid "Bytes:"
@@ -11312,7 +11302,7 @@ msgstr ""
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Snap View"
-msgstr ""
+msgstr "Prichytiť Zobrazenie"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Clip Disabled"
@@ -12361,13 +12351,12 @@ msgid ""
msgstr ""
#: scene/3d/collision_shape.cpp
-#, fuzzy
msgid ""
"A shape must be provided for CollisionShape to function. Please create a "
"shape resource for it."
msgstr ""
-"Musíte nastaviť tvar objektu CollisionShape2D aby fungoval. Prosím, vytvorte "
-"preň tvarový objekt!"
+"Aby CollisionShape fungoval musíte nastaviť tvar. Prosím, vytvorte preň "
+"tvarový objekt."
#: scene/3d/collision_shape.cpp
msgid ""
@@ -12625,9 +12614,8 @@ msgid "Viewport size must be greater than 0 to render anything."
msgstr ""
#: scene/resources/visual_shader_nodes.cpp
-#, fuzzy
msgid "Invalid source for preview."
-msgstr "Nesprávna veľkosť písma."
+msgstr "Neplatný zdroj pre predzobrazenie."
#: scene/resources/visual_shader_nodes.cpp
#, fuzzy
diff --git a/editor/translations/sl.po b/editor/translations/sl.po
index c40bc3b40f..4316ed06b1 100644
--- a/editor/translations/sl.po
+++ b/editor/translations/sl.po
@@ -1193,6 +1193,16 @@ msgid "Gold Sponsors"
msgstr "Zlati Sponzorji"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Srebrni Donatorji"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Bronasti Donatorji"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Majhni Sponzorji"
diff --git a/editor/translations/sq.po b/editor/translations/sq.po
index 2df44bdd5b..7c6d2e2f74 100644
--- a/editor/translations/sq.po
+++ b/editor/translations/sq.po
@@ -1135,6 +1135,16 @@ msgid "Gold Sponsors"
msgstr "Sponsorat Flori"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Dhuruesit Argjend"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Dhuruesit Bronz"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Mini Sponsorat"
diff --git a/editor/translations/sr_Cyrl.po b/editor/translations/sr_Cyrl.po
index 0bb67647f8..84536220b9 100644
--- a/editor/translations/sr_Cyrl.po
+++ b/editor/translations/sr_Cyrl.po
@@ -1250,6 +1250,16 @@ msgid "Gold Sponsors"
msgstr "Златни Ñпонзори"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Сребрни донатори"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Бронзани донатори"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Мали Ñпонзори"
diff --git a/editor/translations/sr_Latn.po b/editor/translations/sr_Latn.po
index 4dece6c33c..b53b92a4e1 100644
--- a/editor/translations/sr_Latn.po
+++ b/editor/translations/sr_Latn.po
@@ -1137,6 +1137,14 @@ msgid "Gold Sponsors"
msgstr ""
#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr ""
diff --git a/editor/translations/sv.po b/editor/translations/sv.po
index d3cda1a61a..d6e91a34b3 100644
--- a/editor/translations/sv.po
+++ b/editor/translations/sv.po
@@ -17,12 +17,13 @@
# Kristoffer Grundström <swedishsailfishosuser@tutanota.com>, 2020.
# Jonas Robertsson <jonas.robertsson@posteo.net>, 2020.
# André Andersson <andre.eric.andersson@gmail.com>, 2020.
+# Andreas Westrell <andreas.westrell@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-07-15 02:42+0000\n"
-"Last-Translator: Jonas Robertsson <jonas.robertsson@posteo.net>\n"
+"PO-Revision-Date: 2020-08-18 02:54+0000\n"
+"Last-Translator: Andreas Westrell <andreas.westrell@gmail.com>\n"
"Language-Team: Swedish <https://hosted.weblate.org/projects/godot-engine/"
"godot/sv/>\n"
"Language: sv\n"
@@ -1150,6 +1151,16 @@ msgid "Gold Sponsors"
msgstr "Guldsponsorer"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Silverdonatorer"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Bronsdonatorer"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Minisponsorer"
@@ -1231,9 +1242,8 @@ msgid "Success!"
msgstr "Klart!"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "Package Contents:"
-msgstr "Innehåll:"
+msgstr "Packet Innehåll:"
#: editor/editor_asset_installer.cpp editor/editor_node.cpp
msgid "Install"
@@ -1256,9 +1266,8 @@ msgid "Rename Audio Bus"
msgstr "Byt namn på Ljud-Buss"
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "Change Audio Bus Volume"
-msgstr "Växla Ljud-Buss Solo"
+msgstr "Växla Ljud-Buss Volum"
#: editor/editor_audio_buses.cpp
msgid "Toggle Audio Bus Solo"
@@ -1385,9 +1394,8 @@ msgid "Add Bus"
msgstr "Lägg till Buss"
#: editor/editor_audio_buses.cpp
-#, fuzzy
msgid "Add a new Audio Bus to this layout."
-msgstr "Spara Ljud-Buss Layout Som..."
+msgstr "Lägg till en ny Audio-Buss för detta layout"
#: editor/editor_audio_buses.cpp editor/editor_properties.cpp
#: editor/plugins/animation_player_editor_plugin.cpp editor/property_editor.cpp
diff --git a/editor/translations/ta.po b/editor/translations/ta.po
index 01cbcc1881..cf057954a2 100644
--- a/editor/translations/ta.po
+++ b/editor/translations/ta.po
@@ -4,13 +4,14 @@
# This file is distributed under the same license as the Godot source code.
#
# Senthil Kumar K <logickumar@gmail.com>, 2017.
-#
+# Survesh VRL <123survesh@gmail.com>, 2020.
+# Sridhar <sreeafmarketing@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2018-12-13 14:43+0100\n"
-"Last-Translator: Senthil Kumar K <logickumar@gmail.com>\n"
+"PO-Revision-Date: 2020-09-01 10:38+0000\n"
+"Last-Translator: Sridhar <sreeafmarketing@gmail.com>\n"
"Language-Team: Tamil <https://hosted.weblate.org/projects/godot-engine/godot/"
"ta/>\n"
"Language: ta\n"
@@ -18,34 +19,37 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Poedit 2.2\n"
+"X-Generator: Weblate 4.2.1-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Invalid type argument to convert(), use TYPE_* constants."
-msgstr ""
+msgstr "தவறான வகை வாதம௠மாறà¯à®±à¯(), TYPE_ * மாறிலிகளைப௠பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤à®µà¯à®®à¯."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
-msgstr ""
+msgstr "நீளமà¯à®³à¯à®³ சொல௠(ஒர௠எழà¯à®¤à¯à®¤à¯) எதிரà¯à®ªà®¾à®°à¯à®•à¯à®•பà¯à®ªà®Ÿà¯à®•ிறதà¯."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Not enough bytes for decoding bytes, or invalid format."
-msgstr ""
+msgstr "டிகோடிங௠போதà¯à®®à®¾à®© பைடà¯à®Ÿà¯à®•ள௠இலà¯à®²à¯ˆ, அலà¯à®²à®¤à¯ தவறான வடிவதà¯à®¤à®¿à®²à¯ உளà¯à®³à®¤à¯."
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
-msgstr ""
+msgstr "தவறான உளà¯à®³à¯€à®Ÿà¯% i (அனà¯à®ªà¯à®ªà®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ) இல௠வெளிபà¯à®ªà®¾à®Ÿà¯à®Ÿà®¿à®²à¯"
#: core/math/expression.cpp
+#, fuzzy
msgid "self can't be used because instance is null (not passed)"
msgstr ""
+"சà¯à®¯à®¤à¯à®¤à¯ˆ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤ à®®à¯à®Ÿà®¿à®¯à®¾à®¤à¯, à®à®©à¯†à®©à®¿à®²à¯ உதாரணமà¯(instance) பூஜà¯à®¯à®®à®¾à®©à®¤à¯ "
+"(நிறைவேறà¯à®±à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ)"
#: core/math/expression.cpp
msgid "Invalid operands to operator %s, %s and %s."
-msgstr ""
+msgstr "ஆபரேடà¯à®Ÿà®°à¯% s,% s மறà¯à®±à¯à®®à¯% s கà¯à®•௠தவறான செயலà¯à®ªà®¾à®Ÿà¯à®•ள௠உளà¯à®³à®¤à¯."
#: core/math/expression.cpp
msgid "Invalid index of type %s for base type %s"
@@ -1129,6 +1133,14 @@ msgid "Gold Sponsors"
msgstr ""
#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr ""
diff --git a/editor/translations/te.po b/editor/translations/te.po
index 3523306b0d..3ad5326ea6 100644
--- a/editor/translations/te.po
+++ b/editor/translations/te.po
@@ -1107,6 +1107,14 @@ msgid "Gold Sponsors"
msgstr ""
#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr ""
diff --git a/editor/translations/th.po b/editor/translations/th.po
index 279f8c08ba..673cca50b2 100644
--- a/editor/translations/th.po
+++ b/editor/translations/th.po
@@ -6,12 +6,13 @@
# Poommetee Ketson (Noshyaar) <poommetee@protonmail.com>, 2017-2018.
# Thanachart Monpassorn <nunf_2539@hotmail.com>, 2020.
# Anonymous <noreply@weblate.org>, 2020.
+# Lon3r <mptube.p@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-05-26 13:41+0000\n"
-"Last-Translator: Thanachart Monpassorn <nunf_2539@hotmail.com>\n"
+"PO-Revision-Date: 2020-08-28 13:09+0000\n"
+"Last-Translator: Lon3r <mptube.p@gmail.com>\n"
"Language-Team: Thai <https://hosted.weblate.org/projects/godot-engine/godot/"
"th/>\n"
"Language: th\n"
@@ -19,7 +20,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.2.1-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -744,9 +745,8 @@ msgid "Method in target node must be specified."
msgstr "ต้องระบุเมธอดในโหนดเป้าหมาย"
#: editor/connections_dialog.cpp
-#, fuzzy
msgid "Method name must be a valid identifier."
-msgstr "ไม่สามารถใช้ชื่อนี้ได้:"
+msgstr "ไม่สามารถใช้ชื่อนี้ได้."
#: editor/connections_dialog.cpp
msgid ""
@@ -1122,6 +1122,16 @@ msgid "Gold Sponsors"
msgstr "ผู้สนับสนุนระดับทอง"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "ผู้บริจาคระดับเงิน"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "ผู้บริจาคระดับทองà¹à¸”ง"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "ผู้สนับสนุน"
@@ -1438,7 +1448,7 @@ msgstr "จัดลำดับออโต้โหลด"
#: editor/editor_autoload_settings.cpp
msgid "Can't add autoload:"
-msgstr ""
+msgstr "เพิ่มออโต้โหลดไม่ได้:"
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -1607,7 +1617,7 @@ msgstr "โหมดเคลื่อนย้าย"
#: editor/editor_feature_profile.cpp
#, fuzzy
msgid "FileSystem and Import Docks"
-msgstr "ระบบไฟล์"
+msgstr "ระบบไฟล์ à¹à¸¥à¸° นำเข้า"
#: editor/editor_feature_profile.cpp
msgid "Erase profile '%s'? (no undo)"
@@ -2051,7 +2061,7 @@ msgstr "à¸à¸³à¸«à¸™à¸”"
#: editor/editor_inspector.cpp
msgid "Set Multiple:"
-msgstr ""
+msgstr "à¸à¸³à¸«à¸™à¸” หลายอย่าง:"
#: editor/editor_log.cpp
msgid "Output:"
@@ -2103,19 +2113,21 @@ msgstr "โหนด"
#: editor/editor_network_profiler.cpp
msgid "Incoming RPC"
-msgstr ""
+msgstr "RPC à¸à¸³à¸¥à¸±à¸‡à¸¡à¸²"
#: editor/editor_network_profiler.cpp
msgid "Incoming RSET"
-msgstr ""
+msgstr "RSET à¸à¸³à¸¥à¸±à¸‡à¸¡à¸²"
#: editor/editor_network_profiler.cpp
+#, fuzzy
msgid "Outgoing RPC"
-msgstr ""
+msgstr "RPC à¸à¸³à¸¥à¸±à¸‡à¸­à¸­à¸"
#: editor/editor_network_profiler.cpp
+#, fuzzy
msgid "Outgoing RSET"
-msgstr ""
+msgstr "RSET à¸à¸³à¸¥à¸±à¸‡à¸­à¸­à¸"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "New Window"
diff --git a/editor/translations/tr.po b/editor/translations/tr.po
index edc01421d2..7710872d7b 100644
--- a/editor/translations/tr.po
+++ b/editor/translations/tr.po
@@ -50,12 +50,13 @@
# Vedat Günel <gunel15@itu.edu.tr>, 2020.
# Ahmet Elgün <ahmetelgn@gmail.com>, 2020.
# Efruz Yıldırır <efruzyildirir@gmail.com>, 2020.
+# Hazar <duurkak@yandex.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-07-06 04:41+0000\n"
-"Last-Translator: Efruz Yıldırır <efruzyildirir@gmail.com>\n"
+"PO-Revision-Date: 2020-08-20 15:20+0000\n"
+"Last-Translator: Hazar <duurkak@yandex.com>\n"
"Language-Team: Turkish <https://hosted.weblate.org/projects/godot-engine/"
"godot/tr/>\n"
"Language: tr\n"
@@ -63,7 +64,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.2-dev\n"
+"X-Generator: Weblate 4.2.1-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1181,6 +1182,16 @@ msgid "Gold Sponsors"
msgstr "Altın Sponsorlar"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Gümüş Bağışçılar"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Bronz Bağışçılar"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Mini Sponsorlar"
@@ -7431,6 +7442,11 @@ msgid ""
"Closed eye: Gizmo is hidden.\n"
"Half-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\")."
msgstr ""
+"Görünürlük ifadelerini değiştirmek için tıklayın.\n"
+"\n"
+"Açık göz: Gizmo görünür.\n"
+"Kapalı göz: Gizmo görünmez.\n"
+"Yarı-açık göz: Gizmo aynı zamanda saydam yüzeylerden görünür (\"x-ray\")."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Nodes To Floor"
@@ -10516,9 +10532,8 @@ msgid "Instance Child Scene"
msgstr "Çocuk Sahnesini Örnekle"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach Script"
-msgstr "Betik İliştir"
+msgstr "Betiği Ayır"
#: editor/scene_tree_dock.cpp
msgid "This operation can't be done on the tree root."
@@ -10555,7 +10570,6 @@ msgid "Make node as Root"
msgstr "Düğümü Kök düğüm yap"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Delete %d nodes and any children?"
msgstr "\"%s\" düğümü ve alt düğümleri silinsin mi?"
@@ -10693,6 +10707,8 @@ msgid ""
"This is probably because this editor was built with all language modules "
"disabled."
msgstr ""
+"Bir yazı eklenemiyor: kayıtlı dil yok.\n"
+"Bu muhtemelen editor tüm dil modülleri kapalıyken kurulduğu için oldu."
#: editor/scene_tree_dock.cpp
msgid "Add Child Node"
@@ -10743,14 +10759,12 @@ msgstr ""
"alınmış bir sahne oluşturur."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Attach a new or existing script to the selected node."
-msgstr "Seçili düğüm için yeni veya mevcut bir betik iliştir."
+msgstr "Seçili düğüme yeni veya mevcut bir betik iliştir."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach the script from the selected node."
-msgstr "Seçilen düğüm için betik temizle."
+msgstr "Seçilen düğümden betiği ayır."
#: editor/scene_tree_dock.cpp
msgid "Remote"
diff --git a/editor/translations/uk.po b/editor/translations/uk.po
index f7386bf72d..a35264b40d 100644
--- a/editor/translations/uk.po
+++ b/editor/translations/uk.po
@@ -1157,6 +1157,16 @@ msgid "Gold Sponsors"
msgstr "Золоті ÑпонÑори"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Срібні донори"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Бронзові донори"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Міні-ÑпонÑори"
diff --git a/editor/translations/ur_PK.po b/editor/translations/ur_PK.po
index 4f4dccd8bb..6b152e43b3 100644
--- a/editor/translations/ur_PK.po
+++ b/editor/translations/ur_PK.po
@@ -1125,6 +1125,14 @@ msgid "Gold Sponsors"
msgstr ""
#: editor/editor_about.cpp
+msgid "Silver Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
+msgid "Bronze Sponsors"
+msgstr ""
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr ""
diff --git a/editor/translations/vi.po b/editor/translations/vi.po
index bd52b850e4..eb260d535e 100644
--- a/editor/translations/vi.po
+++ b/editor/translations/vi.po
@@ -1149,6 +1149,16 @@ msgid "Gold Sponsors"
msgstr "Nhà tài trợ Vàng"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "Ngưá»i á»§ng há»™ Bạc"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "Ngưá»i á»§ng há»™ Äồng"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "Nhà tài trợ Nhá»"
diff --git a/editor/translations/zh_CN.po b/editor/translations/zh_CN.po
index f35da2476c..5d2787f995 100644
--- a/editor/translations/zh_CN.po
+++ b/editor/translations/zh_CN.po
@@ -70,12 +70,13 @@
# Silence Tai <silence.m@hotmail.com>, 2020.
# MintSoda <lionlxh@qq.com>, 2020.
# Gardner Belgrade <hapenia@sina.com>, 2020.
+# godhidden <z2zz2zz@yahoo.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Chinese (Simplified) (Godot Engine)\n"
"POT-Creation-Date: 2018-01-20 12:15+0200\n"
-"PO-Revision-Date: 2020-08-11 14:04+0000\n"
-"Last-Translator: Gardner Belgrade <hapenia@sina.com>\n"
+"PO-Revision-Date: 2020-08-24 13:17+0000\n"
+"Last-Translator: UnluckyNinja <unluckyninja1994@gmail.com>\n"
"Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/"
"godot-engine/godot/zh_Hans/>\n"
"Language: zh_CN\n"
@@ -83,7 +84,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.2-dev\n"
+"X-Generator: Weblate 4.2.1-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1189,6 +1190,16 @@ msgid "Gold Sponsors"
msgstr "黄金赞助"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "白银æèµ è€…"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "é’铜æèµ è€…"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "迷你赞助"
@@ -7014,7 +7025,7 @@ msgstr "转到行..."
#: editor/plugins/script_text_editor.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Toggle Breakpoint"
-msgstr "设置断点"
+msgstr "åˆ‡æ¢æ–­ç‚¹"
#: editor/plugins/script_text_editor.cpp
msgid "Remove All Breakpoints"
@@ -7402,7 +7413,7 @@ msgstr "æ’入动画帧"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Focus Origin"
-msgstr "显示原点"
+msgstr "èšç„¦åŽŸç‚¹"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Focus Selection"
@@ -9402,7 +9413,7 @@ msgstr "包文件"
#: editor/project_export.cpp
msgid "Features"
-msgstr "功能"
+msgstr "特性"
#: editor/project_export.cpp
msgid "Custom (comma-separated):"
diff --git a/editor/translations/zh_HK.po b/editor/translations/zh_HK.po
index d4e1bf62dd..3fdbcd4f76 100644
--- a/editor/translations/zh_HK.po
+++ b/editor/translations/zh_HK.po
@@ -1179,6 +1179,16 @@ msgid "Gold Sponsors"
msgstr "黃金級贊助人"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "ç™½éŠ€ç´šææ¬¾äºº"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "é’éŠ…ç´šææ¬¾äºº"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "迷你贊助人"
diff --git a/editor/translations/zh_TW.po b/editor/translations/zh_TW.po
index 51efdfd2b8..b1cf13ad94 100644
--- a/editor/translations/zh_TW.po
+++ b/editor/translations/zh_TW.po
@@ -1145,6 +1145,16 @@ msgid "Gold Sponsors"
msgstr "黃金贊助"
#: editor/editor_about.cpp
+#, fuzzy
+msgid "Silver Sponsors"
+msgstr "白銀æè´ˆè€…"
+
+#: editor/editor_about.cpp
+#, fuzzy
+msgid "Bronze Sponsors"
+msgstr "紅銅æè´ˆè€…"
+
+#: editor/editor_about.cpp
msgid "Mini Sponsors"
msgstr "迷你贊助"
diff --git a/main/main.cpp b/main/main.cpp
index e45162c0f3..ced8d7227a 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1805,7 +1805,6 @@ bool Main::start() {
}
}
- String main_loop_type;
#ifdef TOOLS_ENABLED
if (doc_tool != "") {
Engine::get_singleton()->set_editor_hint(
@@ -1900,6 +1899,7 @@ bool Main::start() {
if (editor) {
main_loop = memnew(SceneTree);
};
+ String main_loop_type = GLOBAL_DEF("application/run/main_loop_type", "SceneTree");
if (script != "") {
Ref<Script> script_res = ResourceLoader::load(script);
@@ -1930,9 +1930,23 @@ bool Main::start() {
} else {
return false;
}
-
- } else {
- main_loop_type = GLOBAL_DEF("application/run/main_loop_type", "");
+ } else { // Not based on script path.
+ if (!editor && !ClassDB::class_exists(main_loop_type) && ScriptServer::is_global_class(main_loop_type)) {
+ String script_path = ScriptServer::get_global_class_path(main_loop_type);
+ Ref<Script> script_res = ResourceLoader::load(script_path);
+ StringName script_base = ScriptServer::get_global_class_native_base(main_loop_type);
+ Object *obj = ClassDB::instance(script_base);
+ MainLoop *script_loop = Object::cast_to<MainLoop>(obj);
+ if (!script_loop) {
+ if (obj) {
+ memdelete(obj);
+ }
+ DisplayServer::get_singleton()->alert("Error: Invalid MainLoop script base type: " + script_base);
+ ERR_FAIL_V_MSG(false, vformat("The global class %s does not inherit from SceneTree or MainLoop.", main_loop_type));
+ }
+ script_loop->set_init_script(script_res);
+ main_loop = script_loop;
+ }
}
if (!main_loop && main_loop_type == "") {
@@ -2278,6 +2292,13 @@ bool Main::start() {
}
if (project_manager || editor) {
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CONSOLE_WINDOW)) {
+ // Hide console window if requested (Windows-only).
+ bool hide_console = EditorSettings::get_singleton()->get_setting(
+ "interface/editor/hide_console_window");
+ DisplayServer::get_singleton()->console_set_visible(!hide_console);
+ }
+
// Load SSL Certificates from Editor Settings (or builtin)
Crypto::load_default_certificates(EditorSettings::get_singleton()->get_setting(
"network/ssl/editor_ssl_certificates")
diff --git a/methods.py b/methods.py
index 44e381014d..8f14de6dac 100644
--- a/methods.py
+++ b/methods.py
@@ -185,7 +185,7 @@ def write_modules(module_list):
unregister_cpp += "#ifdef MODULE_" + name.upper() + "_ENABLED\n"
unregister_cpp += "\tunregister_" + name + "_types();\n"
unregister_cpp += "#endif\n"
- except IOError:
+ except OSError:
pass
modules_cpp = """// register_module_types.gen.cpp
@@ -522,7 +522,7 @@ def generate_cpp_hint_file(filename):
try:
with open(filename, "w") as fd:
fd.write("#define GDCLASS(m_class, m_inherits)\n")
- except IOError:
+ except OSError:
print("Could not write cpp.hint file.")
@@ -536,6 +536,7 @@ def generate_vs_project(env, num_jobs):
'(if "$(PlatformTarget)"=="x64" (set "plat=x86_amd64"))',
'set "tools=yes"',
'(if "$(Configuration)"=="release" (set "tools=no"))',
+ 'set "custom_modules=%s"' % env["custom_modules"],
'call "' + batch_file + '" !plat!',
]
@@ -555,15 +556,15 @@ def generate_vs_project(env, num_jobs):
# last double quote off, confusing MSBuild
env["MSVSBUILDCOM"] = build_commandline(
"scons --directory=\"$(ProjectDir.TrimEnd('\\'))\" platform=windows progress=no target=$(Configuration)"
- " tools=!tools! -j" + str(num_jobs)
+ " tools=!tools! custom_modules=!custom_modules! -j" + str(num_jobs)
)
env["MSVSREBUILDCOM"] = build_commandline(
"scons --directory=\"$(ProjectDir.TrimEnd('\\'))\" platform=windows progress=no target=$(Configuration)"
- " tools=!tools! vsproj=yes -j" + str(num_jobs)
+ " tools=!tools! custom_modules=!custom_modules! vsproj=yes -j" + str(num_jobs)
)
env["MSVSCLEANCOM"] = build_commandline(
"scons --directory=\"$(ProjectDir.TrimEnd('\\'))\" --clean platform=windows progress=no"
- " target=$(Configuration) tools=!tools! -j" + str(num_jobs)
+ " target=$(Configuration) tools=!tools! custom_modules=!custom_modules! -j" + str(num_jobs)
)
# This version information (Win32, x64, Debug, Release, Release_Debug seems to be
diff --git a/modules/arkit/register_types.h b/modules/arkit/register_types.h
index 5c697baf68..f8939a1e3f 100644
--- a/modules/arkit/register_types.h
+++ b/modules/arkit/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef ARKIT_REGISTER_TYPES_H
+#define ARKIT_REGISTER_TYPES_H
+
void register_arkit_types();
void unregister_arkit_types();
+
+#endif // ARKIT_REGISTER_TYPES_H
diff --git a/modules/basis_universal/texture_basisu.h b/modules/basis_universal/texture_basisu.h
index 8de151ede0..20ecf15a59 100644
--- a/modules/basis_universal/texture_basisu.h
+++ b/modules/basis_universal/texture_basisu.h
@@ -28,6 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef BASIS_UNIVERSAL_TEXTURE_BASISU_H
+#define BASIS_UNIVERSAL_TEXTURE_BASISU_H
+
#include "scene/resources/texture.h"
#ifdef TOOLS_ENABLED
@@ -75,3 +78,5 @@ public:
};
#endif
+
+#endif // BASIS_UNIVERSAL_TEXTURE_BASISU_H
diff --git a/modules/camera/register_types.h b/modules/camera/register_types.h
index f2753cb6d7..e34f84bf2c 100644
--- a/modules/camera/register_types.h
+++ b/modules/camera/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef CAMERA_REGISTER_TYPES_H
+#define CAMERA_REGISTER_TYPES_H
+
void register_camera_types();
void unregister_camera_types();
+
+#endif // CAMERA_REGISTER_TYPES_H
diff --git a/modules/csg/doc_classes/CSGShape3D.xml b/modules/csg/doc_classes/CSGShape3D.xml
index 43ce988c30..dac556c7f1 100644
--- a/modules/csg/doc_classes/CSGShape3D.xml
+++ b/modules/csg/doc_classes/CSGShape3D.xml
@@ -71,10 +71,10 @@
<member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
The physics layers this area is in.
Collidable objects can exist in any of 32 different layers. These layers work like a tagging system, and are not visual. A collidable can use these layers to select with which objects it can collide, using the collision_mask property.
- A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A.
+ A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this CSG shape scans for collisions.
+ The physics layers this CSG shape scans for collisions. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="operation" type="int" setter="set_operation" getter="get_operation" enum="CSGShape3D.Operation" default="0">
The operation that is performed on this shape. This is ignored for the first CSG child node as the operation is between this node and the previous child of this nodes parent.
diff --git a/modules/cvtt/register_types.h b/modules/cvtt/register_types.h
index 8472980c6a..36b5e332d6 100644
--- a/modules/cvtt/register_types.h
+++ b/modules/cvtt/register_types.h
@@ -28,14 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef TOOLS_ENABLED
-
#ifndef CVTT_REGISTER_TYPES_H
#define CVTT_REGISTER_TYPES_H
+#ifdef TOOLS_ENABLED
+
void register_cvtt_types();
void unregister_cvtt_types();
-#endif // CVTT_REGISTER_TYPES_H
-
#endif // TOOLS_ENABLED
+
+#endif // CVTT_REGISTER_TYPES_H
diff --git a/modules/denoise/register_types.h b/modules/denoise/register_types.h
index 2ffc36ee2c..f0f1f44bfe 100644
--- a/modules/denoise/register_types.h
+++ b/modules/denoise/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef DENOISE_REGISTER_TYPES_H
+#define DENOISE_REGISTER_TYPES_H
+
void register_denoise_types();
void unregister_denoise_types();
+
+#endif // DENOISE_REGISTER_TYPES_H
diff --git a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
index c908af7479..f46ef2d812 100644
--- a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
+++ b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
@@ -7,8 +7,8 @@
A PacketPeer implementation that should be passed to [member SceneTree.network_peer] after being initialized as either a client or server. Events can then be handled by connecting to [SceneTree] signals.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/networking/high_level_multiplayer.html</link>
- <link>http://enet.bespin.org/usergroup0.html</link>
+ <link title="High-level multiplayer">https://docs.godotengine.org/en/latest/tutorials/networking/high_level_multiplayer.html</link>
+ <link title="API documentation on the ENet website">http://enet.bespin.org/usergroup0.html</link>
</tutorials>
<methods>
<method name="close_connection">
diff --git a/modules/gdnative/doc_classes/GDNativeLibrary.xml b/modules/gdnative/doc_classes/GDNativeLibrary.xml
index 1aab864102..05cda05f9f 100644
--- a/modules/gdnative/doc_classes/GDNativeLibrary.xml
+++ b/modules/gdnative/doc_classes/GDNativeLibrary.xml
@@ -7,8 +7,8 @@
A GDNative library can implement [NativeScript]s, global functions to call with the [GDNative] class, or low-level engine extensions through interfaces such as [XRInterfaceGDNative]. The library must be compiled for each platform and architecture that the project will run on.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-c-example.html</link>
- <link>https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-cpp-example.html</link>
+ <link title="GDNative C example">https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-c-example.html</link>
+ <link title="GDNative C++ example">https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-cpp-example.html</link>
</tutorials>
<methods>
<method name="get_current_dependencies" qualifiers="const">
diff --git a/modules/gdnative/gdnative/string.cpp b/modules/gdnative/gdnative/string.cpp
index 26c40b625c..1fa19f4ff5 100644
--- a/modules/gdnative/gdnative/string.cpp
+++ b/modules/gdnative/gdnative/string.cpp
@@ -40,9 +40,10 @@
extern "C" {
#endif
+static_assert(sizeof(godot_char16_string) == sizeof(Char16String), "Char16String size mismatch");
static_assert(sizeof(godot_char_string) == sizeof(CharString), "CharString size mismatch");
static_assert(sizeof(godot_string) == sizeof(String), "String size mismatch");
-static_assert(sizeof(godot_char_type) == sizeof(CharType), "CharType size mismatch");
+static_assert(sizeof(godot_char_type) == sizeof(char32_t), "char32_t size mismatch");
godot_int GDAPI godot_char_string_length(const godot_char_string *p_cs) {
const CharString *cs = (const CharString *)p_cs;
@@ -62,6 +63,24 @@ void GDAPI godot_char_string_destroy(godot_char_string *p_cs) {
cs->~CharString();
}
+godot_int GDAPI godot_char16_string_length(const godot_char16_string *p_cs) {
+ const Char16String *cs = (const Char16String *)p_cs;
+
+ return cs->length();
+}
+
+const char16_t GDAPI *godot_char16_string_get_data(const godot_char16_string *p_cs) {
+ const Char16String *cs = (const Char16String *)p_cs;
+
+ return cs->get_data();
+}
+
+void GDAPI godot_char16_string_destroy(godot_char16_string *p_cs) {
+ Char16String *cs = (Char16String *)p_cs;
+
+ cs->~Char16String();
+}
+
void GDAPI godot_string_new(godot_string *r_dest) {
String *dest = (String *)r_dest;
memnew_placement(dest, String);
@@ -70,27 +89,97 @@ void GDAPI godot_string_new(godot_string *r_dest) {
void GDAPI godot_string_new_copy(godot_string *r_dest, const godot_string *p_src) {
String *dest = (String *)r_dest;
const String *src = (const String *)p_src;
- memnew_placement(dest, String(*src));
+ memnew_placement(dest, String);
+ *dest = String(*src);
+}
+
+void GDAPI godot_string_new_with_latin1_chars(godot_string *r_dest, const char *p_contents) {
+ String *dest = (String *)r_dest;
+ memnew_placement(dest, String);
+ *dest = String(p_contents);
+}
+
+void GDAPI godot_string_new_with_utf8_chars(godot_string *r_dest, const char *p_contents) {
+ String *dest = (String *)r_dest;
+ memnew_placement(dest, String);
+ dest->parse_utf8(p_contents);
+}
+
+void GDAPI godot_string_new_with_utf16_chars(godot_string *r_dest, const char16_t *p_contents) {
+ String *dest = (String *)r_dest;
+ memnew_placement(dest, String);
+ dest->parse_utf16(p_contents);
+}
+
+void GDAPI godot_string_new_with_utf32_chars(godot_string *r_dest, const char32_t *p_contents) {
+ String *dest = (String *)r_dest;
+ memnew_placement(dest, String);
+ *dest = String((const char32_t *)p_contents);
+}
+
+void GDAPI godot_string_new_with_wide_chars(godot_string *r_dest, const wchar_t *p_contents) {
+ String *dest = (String *)r_dest;
+ if (sizeof(wchar_t) == 2) {
+ // wchar_t is 16 bit, parse.
+ memnew_placement(dest, String);
+ dest->parse_utf16((const char16_t *)p_contents);
+ } else {
+ // wchar_t is 32 bit, copy.
+ memnew_placement(dest, String);
+ *dest = String((const char32_t *)p_contents);
+ }
+}
+
+void GDAPI godot_string_new_with_latin1_chars_and_len(godot_string *r_dest, const char *p_contents, const int p_size) {
+ String *dest = (String *)r_dest;
+ memnew_placement(dest, String);
+ *dest = String(p_contents, p_size);
+}
+
+void GDAPI godot_string_new_with_utf8_chars_and_len(godot_string *r_dest, const char *p_contents, const int p_size) {
+ String *dest = (String *)r_dest;
+ memnew_placement(dest, String);
+ dest->parse_utf8(p_contents, p_size);
+}
+
+void GDAPI godot_string_new_with_utf16_chars_and_len(godot_string *r_dest, const char16_t *p_contents, const int p_size) {
+ String *dest = (String *)r_dest;
+ memnew_placement(dest, String);
+ dest->parse_utf16(p_contents, p_size);
+}
+
+void GDAPI godot_string_new_with_utf32_chars_and_len(godot_string *r_dest, const char32_t *p_contents, const int p_size) {
+ String *dest = (String *)r_dest;
+ memnew_placement(dest, String);
+ *dest = String((const char32_t *)p_contents, p_size);
}
-void GDAPI godot_string_new_with_wide_string(godot_string *r_dest, const wchar_t *p_contents, const int p_size) {
+void GDAPI godot_string_new_with_wide_chars_and_len(godot_string *r_dest, const wchar_t *p_contents, const int p_size) {
String *dest = (String *)r_dest;
- memnew_placement(dest, String(p_contents, p_size));
+ if (sizeof(wchar_t) == 2) {
+ // wchar_t is 16 bit, parse.
+ memnew_placement(dest, String);
+ dest->parse_utf16((const char16_t *)p_contents, p_size);
+ } else {
+ // wchar_t is 32 bit, copy.
+ memnew_placement(dest, String);
+ *dest = String((const char32_t *)p_contents, p_size);
+ }
}
-const wchar_t GDAPI *godot_string_operator_index(godot_string *p_self, const godot_int p_idx) {
+const godot_char_type GDAPI *godot_string_operator_index(godot_string *p_self, const godot_int p_idx) {
String *self = (String *)p_self;
return &(self->operator[](p_idx));
}
-wchar_t GDAPI godot_string_operator_index_const(const godot_string *p_self, const godot_int p_idx) {
+godot_char_type GDAPI godot_string_operator_index_const(const godot_string *p_self, const godot_int p_idx) {
const String *self = (const String *)p_self;
return self->operator[](p_idx);
}
-const wchar_t GDAPI *godot_string_wide_str(const godot_string *p_self) {
+const godot_char_type GDAPI *godot_string_get_data(const godot_string *p_self) {
const String *self = (const String *)p_self;
- return self->c_str();
+ return self->get_data();
}
godot_bool GDAPI godot_string_operator_equal(const godot_string *p_self, const godot_string *p_b) {
@@ -162,22 +251,14 @@ godot_bool GDAPI godot_string_begins_with_char_array(const godot_string *p_self,
return self->begins_with(p_char_array);
}
-godot_array GDAPI godot_string_bigrams(const godot_string *p_self) {
+godot_packed_string_array GDAPI godot_string_bigrams(const godot_string *p_self) {
const String *self = (const String *)p_self;
- Vector<String> return_value = self->bigrams();
-
- godot_array result;
- memnew_placement(&result, Array);
- Array *proxy = (Array *)&result;
- proxy->resize(return_value.size());
- for (int i = 0; i < return_value.size(); i++) {
- (*proxy)[i] = return_value[i];
- }
-
- return result;
+ godot_packed_string_array ret;
+ memnew_placement(&ret, Vector<String>(self->bigrams()));
+ return ret;
};
-godot_string GDAPI godot_string_chr(wchar_t p_character) {
+godot_string GDAPI godot_string_chr(godot_char_type p_character) {
godot_string result;
memnew_placement(&result, String(String::chr(p_character)));
@@ -191,88 +272,73 @@ godot_bool GDAPI godot_string_ends_with(const godot_string *p_self, const godot_
return self->ends_with(*string);
}
-godot_int GDAPI godot_string_count(const godot_string *p_self, godot_string p_what, godot_int p_from, godot_int p_to) {
+godot_bool GDAPI godot_string_ends_with_char_array(const godot_string *p_self, const char *p_char_array) {
const String *self = (const String *)p_self;
- String *what = (String *)&p_what;
+
+ return self->ends_with(p_char_array);
+}
+
+godot_int GDAPI godot_string_count(const godot_string *p_self, const godot_string *p_what, godot_int p_from, godot_int p_to) {
+ const String *self = (const String *)p_self;
+ const String *what = (const String *)p_what;
return self->count(*what, p_from, p_to);
}
-godot_int GDAPI godot_string_countn(const godot_string *p_self, godot_string p_what, godot_int p_from, godot_int p_to) {
+godot_int GDAPI godot_string_countn(const godot_string *p_self, const godot_string *p_what, godot_int p_from, godot_int p_to) {
const String *self = (const String *)p_self;
- String *what = (String *)&p_what;
+ const String *what = (const String *)p_what;
return self->countn(*what, p_from, p_to);
}
-godot_int GDAPI godot_string_find(const godot_string *p_self, godot_string p_what) {
+godot_int GDAPI godot_string_find(const godot_string *p_self, const godot_string *p_what) {
const String *self = (const String *)p_self;
- String *what = (String *)&p_what;
+ const String *what = (const String *)p_what;
return self->find(*what);
}
-godot_int GDAPI godot_string_find_from(const godot_string *p_self, godot_string p_what, godot_int p_from) {
+godot_int GDAPI godot_string_find_from(const godot_string *p_self, const godot_string *p_what, godot_int p_from) {
const String *self = (const String *)p_self;
- String *what = (String *)&p_what;
+ const String *what = (const String *)p_what;
return self->find(*what, p_from);
}
-godot_int GDAPI godot_string_findmk(const godot_string *p_self, const godot_array *p_keys) {
+godot_int GDAPI godot_string_findmk(const godot_string *p_self, const godot_packed_string_array *p_keys) {
const String *self = (const String *)p_self;
-
- Vector<String> keys;
- Array *keys_proxy = (Array *)p_keys;
- keys.resize(keys_proxy->size());
- for (int i = 0; i < keys_proxy->size(); i++) {
- keys.write[i] = (*keys_proxy)[i];
- }
-
- return self->findmk(keys);
+ const Vector<String> *keys = (const Vector<String> *)p_keys;
+ return self->findmk(*keys);
}
-godot_int GDAPI godot_string_findmk_from(const godot_string *p_self, const godot_array *p_keys, godot_int p_from) {
+godot_int GDAPI godot_string_findmk_from(const godot_string *p_self, const godot_packed_string_array *p_keys, godot_int p_from) {
const String *self = (const String *)p_self;
-
- Vector<String> keys;
- Array *keys_proxy = (Array *)p_keys;
- keys.resize(keys_proxy->size());
- for (int i = 0; i < keys_proxy->size(); i++) {
- keys.write[i] = (*keys_proxy)[i];
- }
-
- return self->findmk(keys, p_from);
+ const Vector<String> *keys = (const Vector<String> *)p_keys;
+ return self->findmk(*keys, p_from);
}
-godot_int GDAPI godot_string_findmk_from_in_place(const godot_string *p_self, const godot_array *p_keys, godot_int p_from, godot_int *r_key) {
+godot_int GDAPI godot_string_findmk_from_in_place(const godot_string *p_self, const godot_packed_string_array *p_keys, godot_int p_from, godot_int *r_key) {
const String *self = (const String *)p_self;
-
- Vector<String> keys;
- Array *keys_proxy = (Array *)p_keys;
- keys.resize(keys_proxy->size());
- for (int i = 0; i < keys_proxy->size(); i++) {
- keys.write[i] = (*keys_proxy)[i];
- }
-
+ const Vector<String> *keys = (const Vector<String> *)p_keys;
int key;
- int ret = self->findmk(keys, p_from, &key);
+ int ret = self->findmk(*keys, p_from, &key);
if (r_key) {
*r_key = key;
}
return ret;
}
-godot_int GDAPI godot_string_findn(const godot_string *p_self, godot_string p_what) {
+godot_int GDAPI godot_string_findn(const godot_string *p_self, const godot_string *p_what) {
const String *self = (const String *)p_self;
- String *what = (String *)&p_what;
+ const String *what = (const String *)p_what;
return self->findn(*what);
}
-godot_int GDAPI godot_string_findn_from(const godot_string *p_self, godot_string p_what, godot_int p_from) {
+godot_int GDAPI godot_string_findn_from(const godot_string *p_self, const godot_string *p_what, godot_int p_from) {
const String *self = (const String *)p_self;
- String *what = (String *)&p_what;
+ const String *what = (const String *)p_what;
return self->findn(*what, p_from);
}
@@ -303,21 +369,9 @@ godot_string GDAPI godot_string_hex_encode_buffer(const uint8_t *p_buffer, godot
return result;
}
-godot_int GDAPI godot_string_hex_to_int(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->hex_to_int();
-}
-
-godot_int GDAPI godot_string_hex_to_int_without_prefix(const godot_string *p_self) {
- const String *self = (const String *)p_self;
-
- return self->hex_to_int(true);
-}
-
-godot_string GDAPI godot_string_insert(const godot_string *p_self, godot_int p_at_pos, godot_string p_string) {
+godot_string GDAPI godot_string_insert(const godot_string *p_self, godot_int p_at_pos, const godot_string *p_string) {
const String *self = (const String *)p_self;
- String *content = (String *)&p_string;
+ const String *content = (const String *)p_string;
godot_string result;
memnew_placement(&result, String(self->insert(p_at_pos, *content)));
@@ -440,58 +494,58 @@ godot_string GDAPI godot_string_pad_zeros(const godot_string *p_self, godot_int
return result;
}
-godot_string GDAPI godot_string_replace(const godot_string *p_self, godot_string p_key, godot_string p_with) {
+godot_string GDAPI godot_string_replace(const godot_string *p_self, const godot_string *p_key, const godot_string *p_with) {
const String *self = (const String *)p_self;
- String *key = (String *)&p_key;
- String *with = (String *)&p_with;
+ const String *key = (const String *)p_key;
+ const String *with = (const String *)p_with;
godot_string result;
memnew_placement(&result, String(self->replace(*key, *with)));
return result;
}
-godot_string GDAPI godot_string_replacen(const godot_string *p_self, godot_string p_key, godot_string p_with) {
+godot_string GDAPI godot_string_replacen(const godot_string *p_self, const godot_string *p_key, const godot_string *p_with) {
const String *self = (const String *)p_self;
- String *key = (String *)&p_key;
- String *with = (String *)&p_with;
+ const String *key = (const String *)p_key;
+ const String *with = (const String *)p_with;
godot_string result;
memnew_placement(&result, String(self->replacen(*key, *with)));
return result;
}
-godot_int GDAPI godot_string_rfind(const godot_string *p_self, godot_string p_what) {
+godot_int GDAPI godot_string_rfind(const godot_string *p_self, const godot_string *p_what) {
const String *self = (const String *)p_self;
- String *what = (String *)&p_what;
+ const String *what = (const String *)p_what;
return self->rfind(*what);
}
-godot_int GDAPI godot_string_rfindn(const godot_string *p_self, godot_string p_what) {
+godot_int GDAPI godot_string_rfindn(const godot_string *p_self, const godot_string *p_what) {
const String *self = (const String *)p_self;
- String *what = (String *)&p_what;
+ const String *what = (const String *)p_what;
return self->rfindn(*what);
}
-godot_int GDAPI godot_string_rfind_from(const godot_string *p_self, godot_string p_what, godot_int p_from) {
+godot_int GDAPI godot_string_rfind_from(const godot_string *p_self, const godot_string *p_what, godot_int p_from) {
const String *self = (const String *)p_self;
- String *what = (String *)&p_what;
+ const String *what = (const String *)p_what;
return self->rfind(*what, p_from);
}
-godot_int GDAPI godot_string_rfindn_from(const godot_string *p_self, godot_string p_what, godot_int p_from) {
+godot_int GDAPI godot_string_rfindn_from(const godot_string *p_self, const godot_string *p_what, godot_int p_from) {
const String *self = (const String *)p_self;
- String *what = (String *)&p_what;
+ const String *what = (const String *)p_what;
return self->rfindn(*what, p_from);
}
-godot_string GDAPI godot_string_replace_first(const godot_string *p_self, godot_string p_key, godot_string p_with) {
+godot_string GDAPI godot_string_replace_first(const godot_string *p_self, const godot_string *p_key, const godot_string *p_with) {
const String *self = (const String *)p_self;
- String *key = (String *)&p_key;
- String *with = (String *)&p_with;
+ const String *key = (const String *)p_key;
+ const String *with = (const String *)p_with;
godot_string result;
memnew_placement(&result, String(self->replace_first(*key, *with)));
@@ -541,16 +595,16 @@ godot_string GDAPI godot_string_substr(const godot_string *p_self, godot_int p_f
return result;
}
-double GDAPI godot_string_to_float(const godot_string *p_self) {
+godot_int GDAPI godot_string_to_int(const godot_string *p_self) {
const String *self = (const String *)p_self;
- return self->to_float();
+ return self->to_int();
}
-godot_int GDAPI godot_string_to_int(const godot_string *p_self) {
+double GDAPI godot_string_to_float(const godot_string *p_self) {
const String *self = (const String *)p_self;
- return self->to_int();
+ return self->to_float();
}
godot_string GDAPI godot_string_capitalize(const godot_string *p_self) {
@@ -581,11 +635,15 @@ double GDAPI godot_string_char_to_float(const char *p_what) {
return String::to_float(p_what);
}
+double GDAPI godot_string_wchar_to_float(const wchar_t *p_str, const wchar_t **r_end) {
+ return String::to_float(p_str, r_end);
+}
+
godot_int GDAPI godot_string_char_to_int(const char *p_what) {
return String::to_int(p_what);
}
-int64_t GDAPI godot_string_wchar_to_int(const wchar_t *p_str) {
+godot_int GDAPI godot_string_wchar_to_int(const wchar_t *p_str) {
return String::to_int(p_str);
}
@@ -593,42 +651,32 @@ godot_int GDAPI godot_string_char_to_int_with_len(const char *p_what, godot_int
return String::to_int(p_what, p_len);
}
-int64_t GDAPI godot_string_char_to_int64_with_len(const wchar_t *p_str, int p_len) {
+godot_int GDAPI godot_string_wchar_to_int_with_len(const wchar_t *p_str, int p_len) {
return String::to_int(p_str, p_len);
}
-int64_t GDAPI godot_string_hex_to_int64(const godot_string *p_self) {
+godot_int GDAPI godot_string_hex_to_int(const godot_string *p_self) {
const String *self = (const String *)p_self;
return self->hex_to_int(false);
}
-int64_t GDAPI godot_string_hex_to_int64_with_prefix(const godot_string *p_self) {
+godot_int GDAPI godot_string_hex_to_int_with_prefix(const godot_string *p_self) {
const String *self = (const String *)p_self;
return self->hex_to_int();
}
-int64_t GDAPI godot_string_to_int64(const godot_string *p_self) {
+godot_string GDAPI godot_string_get_slice(const godot_string *p_self, const godot_string *p_splitter, godot_int p_slice) {
const String *self = (const String *)p_self;
-
- return self->to_int();
-}
-
-double GDAPI godot_string_unicode_char_to_float(const wchar_t *p_str, const wchar_t **r_end) {
- return String::to_float(p_str, r_end);
-}
-
-godot_string GDAPI godot_string_get_slice(const godot_string *p_self, godot_string p_splitter, godot_int p_slice) {
- const String *self = (const String *)p_self;
- String *splitter = (String *)&p_splitter;
+ const String *splitter = (const String *)p_splitter;
godot_string result;
memnew_placement(&result, String(self->get_slice(*splitter, p_slice)));
return result;
}
-godot_string GDAPI godot_string_get_slicec(const godot_string *p_self, wchar_t p_splitter, godot_int p_slice) {
+godot_string GDAPI godot_string_get_slicec(const godot_string *p_self, godot_char_type p_splitter, godot_int p_slice) {
const String *self = (const String *)p_self;
godot_string result;
memnew_placement(&result, String(self->get_slicec(p_splitter, p_slice)));
@@ -636,221 +684,149 @@ godot_string GDAPI godot_string_get_slicec(const godot_string *p_self, wchar_t p
return result;
}
-godot_array GDAPI godot_string_split(const godot_string *p_self, const godot_string *p_splitter) {
+godot_packed_string_array GDAPI godot_string_split(const godot_string *p_self, const godot_string *p_splitter) {
const String *self = (const String *)p_self;
const String *splitter = (const String *)p_splitter;
- godot_array result;
- memnew_placement(&result, Array);
- Array *proxy = (Array *)&result;
- Vector<String> return_value = self->split(*splitter, false);
-
- proxy->resize(return_value.size());
- for (int i = 0; i < return_value.size(); i++) {
- (*proxy)[i] = return_value[i];
- }
-
- return result;
+ godot_packed_string_array ret;
+ memnew_placement(&ret, Vector<String>(self->split(*splitter, false)));
+ return ret;
}
-godot_array GDAPI godot_string_split_allow_empty(const godot_string *p_self, const godot_string *p_splitter) {
+godot_packed_string_array GDAPI godot_string_split_allow_empty(const godot_string *p_self, const godot_string *p_splitter) {
const String *self = (const String *)p_self;
const String *splitter = (const String *)p_splitter;
- godot_array result;
- memnew_placement(&result, Array);
- Array *proxy = (Array *)&result;
- Vector<String> return_value = self->split(*splitter);
-
- proxy->resize(return_value.size());
- for (int i = 0; i < return_value.size(); i++) {
- (*proxy)[i] = return_value[i];
- }
+ godot_packed_string_array ret;
+ memnew_placement(&ret, Vector<String>(self->split(*splitter, true)));
+ return ret;
+}
- return result;
+godot_packed_string_array GDAPI godot_string_split_with_maxsplit(const godot_string *p_self, const godot_string *p_splitter, const godot_bool p_allow_empty, const godot_int p_maxsplit) {
+ const String *self = (const String *)p_self;
+ const String *splitter = (const String *)p_splitter;
+ godot_packed_string_array ret;
+ memnew_placement(&ret, Vector<String>(self->split(*splitter, p_allow_empty, p_maxsplit)));
+ return ret;
}
-godot_array GDAPI godot_string_split_floats(const godot_string *p_self, const godot_string *p_splitter) {
+godot_packed_string_array GDAPI godot_string_rsplit(const godot_string *p_self, const godot_string *p_splitter) {
const String *self = (const String *)p_self;
const String *splitter = (const String *)p_splitter;
- godot_array result;
- memnew_placement(&result, Array);
- Array *proxy = (Array *)&result;
- Vector<float> return_value = self->split_floats(*splitter, false);
-
- proxy->resize(return_value.size());
- for (int i = 0; i < return_value.size(); i++) {
- (*proxy)[i] = return_value[i];
- }
- return result;
+ godot_packed_string_array ret;
+ memnew_placement(&ret, Vector<String>(self->rsplit(*splitter, false)));
+ return ret;
}
-godot_array GDAPI godot_string_split_floats_allows_empty(const godot_string *p_self, const godot_string *p_splitter) {
+godot_packed_string_array GDAPI godot_string_rsplit_allow_empty(const godot_string *p_self, const godot_string *p_splitter) {
const String *self = (const String *)p_self;
const String *splitter = (const String *)p_splitter;
- godot_array result;
- memnew_placement(&result, Array);
- Array *proxy = (Array *)&result;
- Vector<float> return_value = self->split_floats(*splitter);
-
- proxy->resize(return_value.size());
- for (int i = 0; i < return_value.size(); i++) {
- (*proxy)[i] = return_value[i];
- }
- return result;
+ godot_packed_string_array ret;
+ memnew_placement(&ret, Vector<String>(self->rsplit(*splitter, true)));
+ return ret;
}
-godot_array GDAPI godot_string_split_floats_mk(const godot_string *p_self, const godot_array *p_splitters) {
+godot_packed_string_array GDAPI godot_string_rsplit_with_maxsplit(const godot_string *p_self, const godot_string *p_splitter, const godot_bool p_allow_empty, const godot_int p_maxsplit) {
const String *self = (const String *)p_self;
+ const String *splitter = (const String *)p_splitter;
- Vector<String> splitters;
- Array *splitter_proxy = (Array *)p_splitters;
- splitters.resize(splitter_proxy->size());
- for (int i = 0; i < splitter_proxy->size(); i++) {
- splitters.write[i] = (*splitter_proxy)[i];
- }
-
- godot_array result;
- memnew_placement(&result, Array);
- Array *proxy = (Array *)&result;
- Vector<float> return_value = self->split_floats_mk(splitters, false);
+ godot_packed_string_array ret;
+ memnew_placement(&ret, Vector<String>(self->rsplit(*splitter, p_allow_empty, p_maxsplit)));
+ return ret;
+}
- proxy->resize(return_value.size());
- for (int i = 0; i < return_value.size(); i++) {
- (*proxy)[i] = return_value[i];
- }
+godot_packed_float32_array GDAPI godot_string_split_floats(const godot_string *p_self, const godot_string *p_splitter) {
+ const String *self = (const String *)p_self;
+ const String *splitter = (const String *)p_splitter;
- return result;
+ godot_packed_float32_array ret;
+ memnew_placement(&ret, Vector<float>(self->split_floats(*splitter, false)));
+ return ret;
}
-godot_array GDAPI godot_string_split_floats_mk_allows_empty(const godot_string *p_self, const godot_array *p_splitters) {
+godot_packed_float32_array GDAPI godot_string_split_floats_allow_empty(const godot_string *p_self, const godot_string *p_splitter) {
const String *self = (const String *)p_self;
+ const String *splitter = (const String *)p_splitter;
- Vector<String> splitters;
- Array *splitter_proxy = (Array *)p_splitters;
- splitters.resize(splitter_proxy->size());
- for (int i = 0; i < splitter_proxy->size(); i++) {
- splitters.write[i] = (*splitter_proxy)[i];
- }
-
- godot_array result;
- memnew_placement(&result, Array);
- Array *proxy = (Array *)&result;
- Vector<float> return_value = self->split_floats_mk(splitters);
+ godot_packed_float32_array ret;
+ memnew_placement(&ret, Vector<float>(self->split_floats(*splitter, true)));
+ return ret;
+}
- proxy->resize(return_value.size());
- for (int i = 0; i < return_value.size(); i++) {
- (*proxy)[i] = return_value[i];
- }
+godot_packed_float32_array GDAPI godot_string_split_floats_mk(const godot_string *p_self, const godot_packed_string_array *p_splitters) {
+ const String *self = (const String *)p_self;
+ const Vector<String> *splitters = (const Vector<String> *)p_splitters;
- return result;
+ godot_packed_float32_array ret;
+ memnew_placement(&ret, Vector<float>(self->split_floats_mk(*splitters, false)));
+ return ret;
}
-godot_array GDAPI godot_string_split_ints(const godot_string *p_self, const godot_string *p_splitter) {
+godot_packed_float32_array GDAPI godot_string_split_floats_mk_allow_empty(const godot_string *p_self, const godot_packed_string_array *p_splitters) {
const String *self = (const String *)p_self;
- const String *splitter = (const String *)p_splitter;
- godot_array result;
- memnew_placement(&result, Array);
- Array *proxy = (Array *)&result;
- Vector<int> return_value = self->split_ints(*splitter, false);
-
- proxy->resize(return_value.size());
- for (int i = 0; i < return_value.size(); i++) {
- (*proxy)[i] = return_value[i];
- }
+ const Vector<String> *splitters = (const Vector<String> *)p_splitters;
- return result;
+ godot_packed_float32_array ret;
+ memnew_placement(&ret, Vector<float>(self->split_floats_mk(*splitters, true)));
+ return ret;
}
-godot_array GDAPI godot_string_split_ints_allows_empty(const godot_string *p_self, const godot_string *p_splitter) {
+godot_packed_int32_array GDAPI godot_string_split_ints(const godot_string *p_self, const godot_string *p_splitter) {
const String *self = (const String *)p_self;
const String *splitter = (const String *)p_splitter;
- godot_array result;
- memnew_placement(&result, Array);
- Array *proxy = (Array *)&result;
- Vector<int> return_value = self->split_ints(*splitter);
-
- proxy->resize(return_value.size());
- for (int i = 0; i < return_value.size(); i++) {
- (*proxy)[i] = return_value[i];
- }
- return result;
+ godot_packed_int32_array ret;
+ memnew_placement(&ret, Vector<int>(self->split_ints(*splitter, false)));
+ return ret;
}
-godot_array GDAPI godot_string_split_ints_mk(const godot_string *p_self, const godot_array *p_splitters) {
+godot_packed_int32_array GDAPI godot_string_split_ints_allow_empty(const godot_string *p_self, const godot_string *p_splitter) {
const String *self = (const String *)p_self;
+ const String *splitter = (const String *)p_splitter;
- Vector<String> splitters;
- Array *splitter_proxy = (Array *)p_splitters;
- splitters.resize(splitter_proxy->size());
- for (int i = 0; i < splitter_proxy->size(); i++) {
- splitters.write[i] = (*splitter_proxy)[i];
- }
-
- godot_array result;
- memnew_placement(&result, Array);
- Array *proxy = (Array *)&result;
- Vector<int> return_value = self->split_ints_mk(splitters, false);
-
- proxy->resize(return_value.size());
- for (int i = 0; i < return_value.size(); i++) {
- (*proxy)[i] = return_value[i];
- }
-
- return result;
+ godot_packed_int32_array ret;
+ memnew_placement(&ret, Vector<int>(self->split_ints(*splitter, true)));
+ return ret;
}
-godot_array GDAPI godot_string_split_ints_mk_allows_empty(const godot_string *p_self, const godot_array *p_splitters) {
+godot_packed_int32_array GDAPI godot_string_split_ints_mk(const godot_string *p_self, const godot_packed_string_array *p_splitters) {
const String *self = (const String *)p_self;
+ const Vector<String> *splitters = (const Vector<String> *)p_splitters;
- Vector<String> splitters;
- Array *splitter_proxy = (Array *)p_splitters;
- splitters.resize(splitter_proxy->size());
- for (int i = 0; i < splitter_proxy->size(); i++) {
- splitters.write[i] = (*splitter_proxy)[i];
- }
-
- godot_array result;
- memnew_placement(&result, Array);
- Array *proxy = (Array *)&result;
- Vector<int> return_value = self->split_ints_mk(splitters);
+ godot_packed_int32_array ret;
+ memnew_placement(&ret, Vector<int>(self->split_ints_mk(*splitters, false)));
+ return ret;
+}
- proxy->resize(return_value.size());
- for (int i = 0; i < return_value.size(); i++) {
- (*proxy)[i] = return_value[i];
- }
+godot_packed_int32_array GDAPI godot_string_split_ints_mk_allow_empty(const godot_string *p_self, const godot_packed_string_array *p_splitters) {
+ const String *self = (const String *)p_self;
+ const Vector<String> *splitters = (const Vector<String> *)p_splitters;
- return result;
+ godot_packed_int32_array ret;
+ memnew_placement(&ret, Vector<int>(self->split_ints_mk(*splitters, true)));
+ return ret;
}
-godot_array GDAPI godot_string_split_spaces(const godot_string *p_self) {
+godot_packed_string_array GDAPI godot_string_split_spaces(const godot_string *p_self) {
const String *self = (const String *)p_self;
- godot_array result;
- memnew_placement(&result, Array);
- Array *proxy = (Array *)&result;
- Vector<String> return_value = self->split_spaces();
- proxy->resize(return_value.size());
- for (int i = 0; i < return_value.size(); i++) {
- (*proxy)[i] = return_value[i];
- }
-
- return result;
+ godot_packed_string_array ret;
+ memnew_placement(&ret, Vector<String>(self->split_spaces()));
+ return ret;
}
-godot_int GDAPI godot_string_get_slice_count(const godot_string *p_self, godot_string p_splitter) {
+godot_int GDAPI godot_string_get_slice_count(const godot_string *p_self, const godot_string *p_splitter) {
const String *self = (const String *)p_self;
- String *splitter = (String *)&p_splitter;
+ const String *splitter = (const String *)p_splitter;
return self->get_slice_count(*splitter);
}
-wchar_t GDAPI godot_string_char_lowercase(wchar_t p_char) {
+godot_char_type GDAPI godot_string_char_lowercase(godot_char_type p_char) {
return String::char_lowercase(p_char);
}
-wchar_t GDAPI godot_string_char_uppercase(wchar_t p_char) {
+godot_char_type GDAPI godot_string_char_uppercase(godot_char_type p_char) {
return String::char_uppercase(p_char);
}
@@ -894,7 +870,7 @@ godot_string GDAPI godot_string_left(const godot_string *p_self, godot_int p_pos
return result;
}
-wchar_t GDAPI godot_string_ord_at(const godot_string *p_self, godot_int p_idx) {
+godot_char_type GDAPI godot_string_ord_at(const godot_string *p_self, godot_int p_idx) {
const String *self = (const String *)p_self;
return self->ord_at(p_idx);
@@ -917,6 +893,14 @@ godot_string GDAPI godot_string_right(const godot_string *p_self, godot_int p_po
return result;
}
+godot_string GDAPI godot_string_repeat(const godot_string *p_self, godot_int p_count) {
+ const String *self = (const String *)p_self;
+ godot_string result;
+ memnew_placement(&result, String(self->repeat(p_count)));
+
+ return result;
+}
+
godot_string GDAPI godot_string_strip_edges(const godot_string *p_self, godot_bool p_left, godot_bool p_right) {
const String *self = (const String *)p_self;
godot_string result;
@@ -948,7 +932,7 @@ godot_char_string GDAPI godot_string_ascii(const godot_string *p_self) {
return result;
}
-godot_char_string GDAPI godot_string_ascii_extended(const godot_string *p_self) {
+godot_char_string GDAPI godot_string_latin1(const godot_string *p_self) {
const String *self = (const String *)p_self;
godot_char_string result;
@@ -994,6 +978,42 @@ godot_string GDAPI godot_string_chars_to_utf8_with_len(const char *p_utf8, godot
return result;
}
+godot_char16_string GDAPI godot_string_utf16(const godot_string *p_self) {
+ const String *self = (const String *)p_self;
+
+ godot_char16_string result;
+
+ memnew_placement(&result, Char16String(self->utf16()));
+
+ return result;
+}
+
+godot_bool GDAPI godot_string_parse_utf16(godot_string *p_self, const char16_t *p_utf16) {
+ String *self = (String *)p_self;
+
+ return self->parse_utf16(p_utf16);
+}
+
+godot_bool GDAPI godot_string_parse_utf16_with_len(godot_string *p_self, const char16_t *p_utf16, godot_int p_len) {
+ String *self = (String *)p_self;
+
+ return self->parse_utf16(p_utf16, p_len);
+}
+
+godot_string GDAPI godot_string_chars_to_utf16(const char16_t *p_utf16) {
+ godot_string result;
+ memnew_placement(&result, String(String::utf16(p_utf16)));
+
+ return result;
+}
+
+godot_string GDAPI godot_string_chars_to_utf16_with_len(const char16_t *p_utf16, godot_int p_len) {
+ godot_string result;
+ memnew_placement(&result, String(String::utf16(p_utf16, p_len)));
+
+ return result;
+}
+
uint32_t GDAPI godot_string_hash(const godot_string *p_self) {
const String *self = (const String *)p_self;
@@ -1014,28 +1034,18 @@ uint32_t GDAPI godot_string_hash_chars_with_len(const char *p_cstr, godot_int p_
return String::hash(p_cstr, p_len);
}
-uint32_t GDAPI godot_string_hash_utf8_chars(const wchar_t *p_str) {
+uint32_t GDAPI godot_string_hash_wide_chars(const wchar_t *p_str) {
return String::hash(p_str);
}
-uint32_t GDAPI godot_string_hash_utf8_chars_with_len(const wchar_t *p_str, godot_int p_len) {
+uint32_t GDAPI godot_string_hash_wide_chars_with_len(const wchar_t *p_str, godot_int p_len) {
return String::hash(p_str, p_len);
}
godot_packed_byte_array GDAPI godot_string_md5_buffer(const godot_string *p_self) {
const String *self = (const String *)p_self;
- Vector<uint8_t> tmp_result = self->md5_buffer();
-
godot_packed_byte_array result;
- memnew_placement(&result, PackedByteArray);
- PackedByteArray *proxy = (PackedByteArray *)&result;
- uint8_t *proxy_writer = proxy->ptrw();
- proxy->resize(tmp_result.size());
-
- for (int i = 0; i < tmp_result.size(); i++) {
- proxy_writer[i] = tmp_result[i];
- }
-
+ memnew_placement(&result, PackedByteArray(self->md5_buffer()));
return result;
}
@@ -1047,23 +1057,28 @@ godot_string GDAPI godot_string_md5_text(const godot_string *p_self) {
return result;
}
-godot_packed_byte_array GDAPI godot_string_sha256_buffer(const godot_string *p_self) {
+godot_packed_byte_array GDAPI godot_string_sha1_buffer(const godot_string *p_self) {
const String *self = (const String *)p_self;
- Vector<uint8_t> tmp_result = self->sha256_buffer();
-
godot_packed_byte_array result;
- memnew_placement(&result, PackedByteArray);
- PackedByteArray *proxy = (PackedByteArray *)&result;
- uint8_t *proxy_writer = proxy->ptrw();
- proxy->resize(tmp_result.size());
+ memnew_placement(&result, PackedByteArray(self->sha1_buffer()));
+ return result;
+}
- for (int i = 0; i < tmp_result.size(); i++) {
- proxy_writer[i] = tmp_result[i];
- }
+godot_string GDAPI godot_string_sha1_text(const godot_string *p_self) {
+ const String *self = (const String *)p_self;
+ godot_string result;
+ memnew_placement(&result, String(self->sha1_text()));
return result;
}
+godot_packed_byte_array GDAPI godot_string_sha256_buffer(const godot_string *p_self) {
+ const String *self = (const String *)p_self;
+ godot_packed_byte_array result;
+ memnew_placement(&result, PackedByteArray(self->sha256_buffer()));
+ return result;
+}
+
godot_string GDAPI godot_string_sha256_text(const godot_string *p_self) {
const String *self = (const String *)p_self;
godot_string result;
@@ -1206,15 +1221,6 @@ godot_string GDAPI godot_string_json_escape(const godot_string *p_self) {
return result;
}
-godot_string GDAPI godot_string_word_wrap(const godot_string *p_self, godot_int p_chars_per_line) {
- const String *self = (const String *)p_self;
- godot_string result;
- String return_value = self->word_wrap(p_chars_per_line);
- memnew_placement(&result, String(return_value));
-
- return result;
-}
-
godot_string GDAPI godot_string_xml_escape(const godot_string *p_self) {
const String *self = (const String *)p_self;
godot_string result;
@@ -1260,6 +1266,22 @@ godot_string GDAPI godot_string_percent_encode(const godot_string *p_self) {
return result;
}
+godot_string GDAPI godot_string_join(const godot_string *p_self, const godot_packed_string_array *p_parts) {
+ const String *self = (const String *)p_self;
+ const Vector<String> *parts = (const Vector<String> *)p_parts;
+ godot_string result;
+ String return_value = self->join(*parts);
+ memnew_placement(&result, String(return_value));
+
+ return result;
+}
+
+godot_bool GDAPI godot_string_is_valid_filename(const godot_string *p_self) {
+ const String *self = (const String *)p_self;
+
+ return self->is_valid_filename();
+}
+
godot_bool GDAPI godot_string_is_valid_float(const godot_string *p_self) {
const String *self = (const String *)p_self;
@@ -1325,31 +1347,22 @@ godot_string GDAPI godot_string_trim_suffix(const godot_string *p_self, const go
return result;
}
-godot_string GDAPI godot_string_rstrip(const godot_string *p_self, const godot_string *p_chars) {
+godot_string GDAPI godot_string_lstrip(const godot_string *p_self, const godot_string *p_chars) {
const String *self = (const String *)p_self;
String *chars = (String *)p_chars;
godot_string result;
- String return_value = self->rstrip(*chars);
+ String return_value = self->lstrip(*chars);
memnew_placement(&result, String(return_value));
return result;
}
-godot_packed_string_array GDAPI godot_string_rsplit(const godot_string *p_self, const godot_string *p_divisor,
- const godot_bool p_allow_empty, const godot_int p_maxsplit) {
+godot_string GDAPI godot_string_rstrip(const godot_string *p_self, const godot_string *p_chars) {
const String *self = (const String *)p_self;
- String *divisor = (String *)p_divisor;
-
- godot_packed_string_array result;
- memnew_placement(&result, PackedStringArray);
- PackedStringArray *proxy = (PackedStringArray *)&result;
- String *proxy_writer = proxy->ptrw();
- Vector<String> tmp_result = self->rsplit(*divisor, p_allow_empty, p_maxsplit);
- proxy->resize(tmp_result.size());
-
- for (int i = 0; i < tmp_result.size(); i++) {
- proxy_writer[i] = tmp_result[i];
- }
+ String *chars = (String *)p_chars;
+ godot_string result;
+ String return_value = self->rstrip(*chars);
+ memnew_placement(&result, String(return_value));
return result;
}
diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json
index 8ccf44ff1a..82bfbd23de 100644
--- a/modules/gdnative/gdnative_api.json
+++ b/modules/gdnative/gdnative_api.json
@@ -3732,6 +3732,27 @@
]
},
{
+ "name": "godot_char16_string_length",
+ "return_type": "godot_int",
+ "arguments": [
+ ["const godot_char16_string *", "p_cs"]
+ ]
+ },
+ {
+ "name": "godot_char16_string_get_data",
+ "return_type": "const char16_t *",
+ "arguments": [
+ ["const godot_char16_string *", "p_cs"]
+ ]
+ },
+ {
+ "name": "godot_char16_string_destroy",
+ "return_type": "void",
+ "arguments": [
+ ["godot_char16_string *", "p_cs"]
+ ]
+ },
+ {
"name": "godot_string_new",
"return_type": "void",
"arguments": [
@@ -3747,7 +3768,83 @@
]
},
{
- "name": "godot_string_new_with_wide_string",
+ "name": "godot_string_new_with_latin1_chars",
+ "return_type": "void",
+ "arguments": [
+ ["godot_string *", "r_dest"],
+ ["const char *", "p_contents"]
+ ]
+ },
+ {
+ "name": "godot_string_new_with_utf8_chars",
+ "return_type": "void",
+ "arguments": [
+ ["godot_string *", "r_dest"],
+ ["const char *", "p_contents"]
+ ]
+ },
+ {
+ "name": "godot_string_new_with_utf16_chars",
+ "return_type": "void",
+ "arguments": [
+ ["godot_string *", "r_dest"],
+ ["const char16_t *", "p_contents"]
+ ]
+ },
+ {
+ "name": "godot_string_new_with_utf32_chars",
+ "return_type": "void",
+ "arguments": [
+ ["godot_string *", "r_dest"],
+ ["const char32_t *", "p_contents"]
+ ]
+ },
+ {
+ "name": "godot_string_new_with_wide_chars",
+ "return_type": "void",
+ "arguments": [
+ ["godot_string *", "r_dest"],
+ ["const wchar_t *", "p_contents"]
+ ]
+ },
+ {
+ "name": "godot_string_new_with_latin1_chars_and_len",
+ "return_type": "void",
+ "arguments": [
+ ["godot_string *", "r_dest"],
+ ["const char *", "p_contents"],
+ ["const int", "p_size"]
+ ]
+ },
+ {
+ "name": "godot_string_new_with_utf8_chars_and_len",
+ "return_type": "void",
+ "arguments": [
+ ["godot_string *", "r_dest"],
+ ["const char *", "p_contents"],
+ ["const int", "p_size"]
+ ]
+ },
+ {
+ "name": "godot_string_new_with_utf16_chars_and_len",
+ "return_type": "void",
+ "arguments": [
+ ["godot_string *", "r_dest"],
+ ["const char16_t *", "p_contents"],
+ ["const int", "p_size"]
+ ]
+ },
+ {
+ "name": "godot_string_new_with_utf32_chars_and_len",
+ "return_type": "void",
+ "arguments": [
+ ["godot_string *", "r_dest"],
+ ["const char32_t *", "p_contents"],
+ ["const int", "p_size"]
+ ]
+ },
+ {
+ "name": "godot_string_new_with_wide_chars_and_len",
"return_type": "void",
"arguments": [
["godot_string *", "r_dest"],
@@ -3757,7 +3854,7 @@
},
{
"name": "godot_string_operator_index",
- "return_type": "const wchar_t *",
+ "return_type": "const godot_char_type *",
"arguments": [
["godot_string *", "p_self"],
["const godot_int", "p_idx"]
@@ -3765,15 +3862,15 @@
},
{
"name": "godot_string_operator_index_const",
- "return_type": "wchar_t",
+ "return_type": "godot_char_type",
"arguments": [
["const godot_string *", "p_self"],
["const godot_int", "p_idx"]
]
},
{
- "name": "godot_string_wide_str",
- "return_type": "const wchar_t *",
+ "name": "godot_string_get_data",
+ "return_type": "const godot_char_type *",
"arguments": [
["const godot_string *", "p_self"]
]
@@ -3807,7 +3904,7 @@
"return_type": "godot_int",
"arguments": [
["const godot_string *", "p_self"],
- ["godot_string", "p_what"],
+ ["const godot_string *", "p_what"],
["godot_int", "p_from"],
["godot_int", "p_to"]
]
@@ -3817,7 +3914,7 @@
"return_type": "godot_int",
"arguments": [
["const godot_string *", "p_self"],
- ["godot_string", "p_what"],
+ ["const godot_string *", "p_what"],
["godot_int", "p_from"],
["godot_int", "p_to"]
]
@@ -3878,7 +3975,7 @@
},
{
"name": "godot_string_bigrams",
- "return_type": "godot_array",
+ "return_type": "godot_packed_string_array",
"arguments": [
["const godot_string *", "p_self"]
]
@@ -3887,7 +3984,7 @@
"name": "godot_string_chr",
"return_type": "godot_string",
"arguments": [
- ["wchar_t", "p_character"]
+ ["godot_char_type", "p_character"]
]
},
{
@@ -3899,11 +3996,19 @@
]
},
{
+ "name": "godot_string_ends_with_char_array",
+ "return_type": "godot_bool",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const char *", "p_char_array"]
+ ]
+ },
+ {
"name": "godot_string_find",
"return_type": "godot_int",
"arguments": [
["const godot_string *", "p_self"],
- ["godot_string", "p_what"]
+ ["const godot_string *", "p_what"]
]
},
{
@@ -3911,7 +4016,7 @@
"return_type": "godot_int",
"arguments": [
["const godot_string *", "p_self"],
- ["godot_string", "p_what"],
+ ["const godot_string *", "p_what"],
["godot_int", "p_from"]
]
},
@@ -3920,7 +4025,7 @@
"return_type": "godot_int",
"arguments": [
["const godot_string *", "p_self"],
- ["const godot_array *", "p_keys"]
+ ["const godot_packed_string_array *", "p_keys"]
]
},
{
@@ -3928,7 +4033,7 @@
"return_type": "godot_int",
"arguments": [
["const godot_string *", "p_self"],
- ["const godot_array *", "p_keys"],
+ ["const godot_packed_string_array *", "p_keys"],
["godot_int", "p_from"]
]
},
@@ -3937,7 +4042,7 @@
"return_type": "godot_int",
"arguments": [
["const godot_string *", "p_self"],
- ["const godot_array *", "p_keys"],
+ ["const godot_packed_string_array *", "p_keys"],
["godot_int", "p_from"],
["godot_int *", "r_key"]
]
@@ -3947,7 +4052,7 @@
"return_type": "godot_int",
"arguments": [
["const godot_string *", "p_self"],
- ["godot_string", "p_what"]
+ ["const godot_string *", "p_what"]
]
},
{
@@ -3955,7 +4060,7 @@
"return_type": "godot_int",
"arguments": [
["const godot_string *", "p_self"],
- ["godot_string", "p_what"],
+ ["const godot_string *", "p_what"],
["godot_int", "p_from"]
]
},
@@ -3985,26 +4090,12 @@
]
},
{
- "name": "godot_string_hex_to_int",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_hex_to_int_without_prefix",
- "return_type": "godot_int",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
"name": "godot_string_insert",
"return_type": "godot_string",
"arguments": [
["const godot_string *", "p_self"],
["godot_int", "p_at_pos"],
- ["godot_string", "p_string"]
+ ["const godot_string *", "p_string"]
]
},
{
@@ -4137,8 +4228,8 @@
"return_type": "godot_string",
"arguments": [
["const godot_string *", "p_self"],
- ["godot_string", "p_key"],
- ["godot_string", "p_with"]
+ ["const godot_string *", "p_key"],
+ ["const godot_string *", "p_with"]
]
},
{
@@ -4146,8 +4237,8 @@
"return_type": "godot_string",
"arguments": [
["const godot_string *", "p_self"],
- ["godot_string", "p_key"],
- ["godot_string", "p_with"]
+ ["const godot_string *", "p_key"],
+ ["const godot_string *", "p_with"]
]
},
{
@@ -4155,8 +4246,8 @@
"return_type": "godot_string",
"arguments": [
["const godot_string *", "p_self"],
- ["godot_string", "p_key"],
- ["godot_string", "p_with"]
+ ["const godot_string *", "p_key"],
+ ["const godot_string *", "p_with"]
]
},
{
@@ -4164,7 +4255,7 @@
"return_type": "godot_int",
"arguments": [
["const godot_string *", "p_self"],
- ["godot_string", "p_what"]
+ ["const godot_string *", "p_what"]
]
},
{
@@ -4172,7 +4263,7 @@
"return_type": "godot_int",
"arguments": [
["const godot_string *", "p_self"],
- ["godot_string", "p_what"]
+ ["const godot_string *", "p_what"]
]
},
{
@@ -4180,7 +4271,7 @@
"return_type": "godot_int",
"arguments": [
["const godot_string *", "p_self"],
- ["godot_string", "p_what"],
+ ["const godot_string *", "p_what"],
["godot_int", "p_from"]
]
},
@@ -4189,7 +4280,7 @@
"return_type": "godot_int",
"arguments": [
["const godot_string *", "p_self"],
- ["godot_string", "p_what"],
+ ["const godot_string *", "p_what"],
["godot_int", "p_from"]
]
},
@@ -4237,15 +4328,15 @@
]
},
{
- "name": "godot_string_to_float",
- "return_type": "double",
+ "name": "godot_string_to_int",
+ "return_type": "godot_int",
"arguments": [
["const godot_string *", "p_self"]
]
},
{
- "name": "godot_string_to_int",
- "return_type": "godot_int",
+ "name": "godot_string_to_float",
+ "return_type": "double",
"arguments": [
["const godot_string *", "p_self"]
]
@@ -4279,6 +4370,14 @@
]
},
{
+ "name": "godot_string_wchar_to_float",
+ "return_type": "double",
+ "arguments": [
+ ["const wchar_t *", "p_str"],
+ ["const wchar_t **", "r_end"]
+ ]
+ },
+ {
"name": "godot_string_char_to_int",
"return_type": "godot_int",
"arguments": [
@@ -4287,7 +4386,7 @@
},
{
"name": "godot_string_wchar_to_int",
- "return_type": "int64_t",
+ "return_type": "godot_int",
"arguments": [
["const wchar_t *", "p_str"]
]
@@ -4301,48 +4400,33 @@
]
},
{
- "name": "godot_string_char_to_int64_with_len",
- "return_type": "int64_t",
+ "name": "godot_string_wchar_to_int_with_len",
+ "return_type": "godot_int",
"arguments": [
["const wchar_t *", "p_str"],
["int", "p_len"]
]
},
{
- "name": "godot_string_hex_to_int64",
- "return_type": "int64_t",
- "arguments": [
- ["const godot_string *", "p_self"]
- ]
- },
- {
- "name": "godot_string_hex_to_int64_with_prefix",
- "return_type": "int64_t",
+ "name": "godot_string_hex_to_int",
+ "return_type": "godot_int",
"arguments": [
["const godot_string *", "p_self"]
]
},
{
- "name": "godot_string_to_int64",
- "return_type": "int64_t",
+ "name": "godot_string_hex_to_int_with_prefix",
+ "return_type": "godot_int",
"arguments": [
["const godot_string *", "p_self"]
]
},
{
- "name": "godot_string_unicode_char_to_float",
- "return_type": "double",
- "arguments": [
- ["const wchar_t *", "p_str"],
- ["const wchar_t **", "r_end"]
- ]
- },
- {
"name": "godot_string_get_slice_count",
"return_type": "godot_int",
"arguments": [
["const godot_string *", "p_self"],
- ["godot_string", "p_splitter"]
+ ["const godot_string *", "p_splitter"]
]
},
{
@@ -4350,7 +4434,7 @@
"return_type": "godot_string",
"arguments": [
["const godot_string *", "p_self"],
- ["godot_string", "p_splitter"],
+ ["const godot_string *", "p_splitter"],
["godot_int", "p_slice"]
]
},
@@ -4359,13 +4443,13 @@
"return_type": "godot_string",
"arguments": [
["const godot_string *", "p_self"],
- ["wchar_t", "p_splitter"],
+ ["godot_char_type", "p_splitter"],
["godot_int", "p_slice"]
]
},
{
"name": "godot_string_split",
- "return_type": "godot_array",
+ "return_type": "godot_packed_string_array",
"arguments": [
["const godot_string *", "p_self"],
["const godot_string *", "p_splitter"]
@@ -4373,23 +4457,59 @@
},
{
"name": "godot_string_split_allow_empty",
- "return_type": "godot_array",
+ "return_type": "godot_packed_string_array",
"arguments": [
["const godot_string *", "p_self"],
["const godot_string *", "p_splitter"]
]
},
{
+ "name": "godot_string_split_with_maxsplit",
+ "return_type": "godot_packed_string_array",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_string *", "p_splitter"],
+ ["const godot_bool", "p_allow_empty"],
+ ["const godot_int", "p_maxsplit"]
+ ]
+ },
+ {
+ "name": "godot_string_rsplit",
+ "return_type": "godot_packed_string_array",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_string *", "p_splitter"]
+ ]
+ },
+ {
+ "name": "godot_string_rsplit_allow_empty",
+ "return_type": "godot_packed_string_array",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_string *", "p_splitter"]
+ ]
+ },
+ {
+ "name": "godot_string_rsplit_with_maxsplit",
+ "return_type": "godot_packed_string_array",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_string *", "p_splitter"],
+ ["const godot_bool", "p_allow_empty"],
+ ["const godot_int", "p_maxsplit"]
+ ]
+ },
+ {
"name": "godot_string_split_floats",
- "return_type": "godot_array",
+ "return_type": "godot_packed_float32_array",
"arguments": [
["const godot_string *", "p_self"],
["const godot_string *", "p_splitter"]
]
},
{
- "name": "godot_string_split_floats_allows_empty",
- "return_type": "godot_array",
+ "name": "godot_string_split_floats_allow_empty",
+ "return_type": "godot_packed_float32_array",
"arguments": [
["const godot_string *", "p_self"],
["const godot_string *", "p_splitter"]
@@ -4397,31 +4517,31 @@
},
{
"name": "godot_string_split_floats_mk",
- "return_type": "godot_array",
+ "return_type": "godot_packed_float32_array",
"arguments": [
["const godot_string *", "p_self"],
- ["const godot_array *", "p_splitters"]
+ ["const godot_packed_string_array *", "p_splitters"]
]
},
{
- "name": "godot_string_split_floats_mk_allows_empty",
- "return_type": "godot_array",
+ "name": "godot_string_split_floats_mk_allow_empty",
+ "return_type": "godot_packed_float32_array",
"arguments": [
["const godot_string *", "p_self"],
- ["const godot_array *", "p_splitters"]
+ ["const godot_packed_string_array *", "p_splitters"]
]
},
{
"name": "godot_string_split_ints",
- "return_type": "godot_array",
+ "return_type": "godot_packed_int32_array",
"arguments": [
["const godot_string *", "p_self"],
["const godot_string *", "p_splitter"]
]
},
{
- "name": "godot_string_split_ints_allows_empty",
- "return_type": "godot_array",
+ "name": "godot_string_split_ints_allow_empty",
+ "return_type": "godot_packed_int32_array",
"arguments": [
["const godot_string *", "p_self"],
["const godot_string *", "p_splitter"]
@@ -4429,29 +4549,29 @@
},
{
"name": "godot_string_split_ints_mk",
- "return_type": "godot_array",
+ "return_type": "godot_packed_int32_array",
"arguments": [
["const godot_string *", "p_self"],
- ["const godot_array *", "p_splitters"]
+ ["const godot_packed_string_array *", "p_splitters"]
]
},
{
- "name": "godot_string_split_ints_mk_allows_empty",
- "return_type": "godot_array",
+ "name": "godot_string_split_ints_mk_allow_empty",
+ "return_type": "godot_packed_int32_array",
"arguments": [
["const godot_string *", "p_self"],
- ["const godot_array *", "p_splitters"]
+ ["const godot_packed_string_array *", "p_splitters"]
]
},
{
"name": "godot_string_split_spaces",
- "return_type": "godot_array",
+ "return_type": "godot_packed_string_array",
"arguments": [
["const godot_string *", "p_self"]
]
},
{
- "name": "godot_string_rstrip",
+ "name": "godot_string_lstrip",
"return_type": "godot_string",
"arguments": [
["const godot_string *", "p_self"],
@@ -4459,13 +4579,11 @@
]
},
{
- "name": "godot_string_rsplit",
- "return_type": "godot_packed_string_array",
+ "name": "godot_string_rstrip",
+ "return_type": "godot_string",
"arguments": [
["const godot_string *", "p_self"],
- ["const godot_string *", "p_divisor"],
- ["const godot_bool", "p_allow_empty"],
- ["const godot_int", "p_maxsplit"]
+ ["const godot_string *", "p_chars"]
]
},
{
@@ -4486,16 +4604,16 @@
},
{
"name": "godot_string_char_lowercase",
- "return_type": "wchar_t",
+ "return_type": "godot_char_type",
"arguments": [
- ["wchar_t", "p_char"]
+ ["godot_char_type", "p_char"]
]
},
{
"name": "godot_string_char_uppercase",
- "return_type": "wchar_t",
+ "return_type": "godot_char_type",
"arguments": [
- ["wchar_t", "p_char"]
+ ["godot_char_type", "p_char"]
]
},
{
@@ -4536,7 +4654,7 @@
},
{
"name": "godot_string_ord_at",
- "return_type": "wchar_t",
+ "return_type": "godot_char_type",
"arguments": [
["const godot_string *", "p_self"],
["godot_int", "p_idx"]
@@ -4559,6 +4677,14 @@
]
},
{
+ "name": "godot_string_repeat",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["godot_int", "p_count"]
+ ]
+ },
+ {
"name": "godot_string_strip_edges",
"return_type": "godot_string",
"arguments": [
@@ -4591,7 +4717,7 @@
]
},
{
- "name": "godot_string_ascii_extended",
+ "name": "godot_string_latin1",
"return_type": "godot_char_string",
"arguments": [
["const godot_string *", "p_self"]
@@ -4622,17 +4748,26 @@
]
},
{
- "name": "godot_string_chars_to_utf8",
- "return_type": "godot_string",
+ "name": "godot_string_utf16",
+ "return_type": "godot_char16_string",
"arguments": [
- ["const char *", "p_utf8"]
+ ["const godot_string *", "p_self"]
]
},
{
- "name": "godot_string_chars_to_utf8_with_len",
- "return_type": "godot_string",
+ "name": "godot_string_parse_utf16",
+ "return_type": "godot_bool",
"arguments": [
- ["const char *", "p_utf8"],
+ ["godot_string *", "p_self"],
+ ["const char16_t *", "p_utf16"]
+ ]
+ },
+ {
+ "name": "godot_string_parse_utf16_with_len",
+ "return_type": "godot_bool",
+ "arguments": [
+ ["godot_string *", "p_self"],
+ ["const char16_t *", "p_utf16"],
["godot_int", "p_len"]
]
},
@@ -4666,14 +4801,14 @@
]
},
{
- "name": "godot_string_hash_utf8_chars",
+ "name": "godot_string_hash_wide_chars",
"return_type": "uint32_t",
"arguments": [
["const wchar_t *", "p_str"]
]
},
{
- "name": "godot_string_hash_utf8_chars_with_len",
+ "name": "godot_string_hash_wide_chars_with_len",
"return_type": "uint32_t",
"arguments": [
["const wchar_t *", "p_str"],
@@ -4695,6 +4830,20 @@
]
},
{
+ "name": "godot_string_sha1_buffer",
+ "return_type": "godot_packed_byte_array",
+ "arguments": [
+ ["const godot_string *", "p_self"]
+ ]
+ },
+ {
+ "name": "godot_string_sha1_text",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const godot_string *", "p_self"]
+ ]
+ },
+ {
"name": "godot_string_sha256_buffer",
"return_type": "godot_packed_byte_array",
"arguments": [
@@ -4823,14 +4972,6 @@
]
},
{
- "name": "godot_string_word_wrap",
- "return_type": "godot_string",
- "arguments": [
- ["const godot_string *", "p_self"],
- ["godot_int", "p_chars_per_line"]
- ]
- },
- {
"name": "godot_string_xml_escape",
"return_type": "godot_string",
"arguments": [
@@ -4866,6 +5007,21 @@
]
},
{
+ "name": "godot_string_join",
+ "return_type": "godot_string",
+ "arguments": [
+ ["const godot_string *", "p_self"],
+ ["const godot_packed_string_array *", "p_parts"]
+ ]
+ },
+ {
+ "name": "godot_string_is_valid_filename",
+ "return_type": "godot_bool",
+ "arguments": [
+ ["const godot_string *", "p_self"]
+ ]
+ },
+ {
"name": "godot_string_is_valid_float",
"return_type": "godot_bool",
"arguments": [
diff --git a/modules/gdnative/include/gdnative/string.h b/modules/gdnative/include/gdnative/string.h
index d89383dc1b..0582d95f63 100644
--- a/modules/gdnative/include/gdnative/string.h
+++ b/modules/gdnative/include/gdnative/string.h
@@ -38,10 +38,11 @@ extern "C" {
#include <stdint.h>
#include <wchar.h>
-typedef wchar_t godot_char_type;
+typedef char32_t godot_char_type;
#define GODOT_STRING_SIZE sizeof(void *)
#define GODOT_CHAR_STRING_SIZE sizeof(void *)
+#define GODOT_CHAR16_STRING_SIZE sizeof(void *)
#ifndef GODOT_CORE_API_GODOT_STRING_TYPE_DEFINED
#define GODOT_CORE_API_GODOT_STRING_TYPE_DEFINED
@@ -58,6 +59,13 @@ typedef struct {
} godot_char_string;
#endif
+#ifndef GODOT_CORE_API_GODOT_CHAR16_STRING_TYPE_DEFINED
+#define GODOT_CORE_API_GODOT_CHAR16_STRING_TYPE_DEFINED
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_CHAR16_STRING_SIZE];
+} godot_char16_string;
+#endif
+
// reduce extern "C" nesting for VS2013
#ifdef __cplusplus
}
@@ -75,13 +83,28 @@ godot_int GDAPI godot_char_string_length(const godot_char_string *p_cs);
const char GDAPI *godot_char_string_get_data(const godot_char_string *p_cs);
void GDAPI godot_char_string_destroy(godot_char_string *p_cs);
+godot_int GDAPI godot_char16_string_length(const godot_char16_string *p_cs);
+const char16_t GDAPI *godot_char16_string_get_data(const godot_char16_string *p_cs);
+void GDAPI godot_char16_string_destroy(godot_char16_string *p_cs);
+
void GDAPI godot_string_new(godot_string *r_dest);
void GDAPI godot_string_new_copy(godot_string *r_dest, const godot_string *p_src);
-void GDAPI godot_string_new_with_wide_string(godot_string *r_dest, const wchar_t *p_contents, const int p_size);
-const wchar_t GDAPI *godot_string_operator_index(godot_string *p_self, const godot_int p_idx);
-wchar_t GDAPI godot_string_operator_index_const(const godot_string *p_self, const godot_int p_idx);
-const wchar_t GDAPI *godot_string_wide_str(const godot_string *p_self);
+void GDAPI godot_string_new_with_latin1_chars(godot_string *r_dest, const char *p_contents);
+void GDAPI godot_string_new_with_utf8_chars(godot_string *r_dest, const char *p_contents);
+void GDAPI godot_string_new_with_utf16_chars(godot_string *r_dest, const char16_t *p_contents);
+void GDAPI godot_string_new_with_utf32_chars(godot_string *r_dest, const char32_t *p_contents);
+void GDAPI godot_string_new_with_wide_chars(godot_string *r_dest, const wchar_t *p_contents);
+
+void GDAPI godot_string_new_with_latin1_chars_and_len(godot_string *r_dest, const char *p_contents, const int p_size);
+void GDAPI godot_string_new_with_utf8_chars_and_len(godot_string *r_dest, const char *p_contents, const int p_size);
+void GDAPI godot_string_new_with_utf16_chars_and_len(godot_string *r_dest, const char16_t *p_contents, const int p_size);
+void GDAPI godot_string_new_with_utf32_chars_and_len(godot_string *r_dest, const char32_t *p_contents, const int p_size);
+void GDAPI godot_string_new_with_wide_chars_and_len(godot_string *r_dest, const wchar_t *p_contents, const int p_size);
+
+const godot_char_type GDAPI *godot_string_operator_index(godot_string *p_self, const godot_int p_idx);
+godot_char_type GDAPI godot_string_operator_index_const(const godot_string *p_self, const godot_int p_idx);
+const godot_char_type GDAPI *godot_string_get_data(const godot_string *p_self);
godot_bool GDAPI godot_string_operator_equal(const godot_string *p_self, const godot_string *p_b);
godot_bool GDAPI godot_string_operator_less(const godot_string *p_self, const godot_string *p_b);
@@ -89,7 +112,7 @@ godot_string GDAPI godot_string_operator_plus(const godot_string *p_self, const
/* Standard size stuff */
-godot_int GDAPI godot_string_length(const godot_string *p_self);
+/*+++*/ godot_int GDAPI godot_string_length(const godot_string *p_self);
/* Helpers */
@@ -99,24 +122,25 @@ signed char GDAPI godot_string_naturalnocasecmp_to(const godot_string *p_self, c
godot_bool GDAPI godot_string_begins_with(const godot_string *p_self, const godot_string *p_string);
godot_bool GDAPI godot_string_begins_with_char_array(const godot_string *p_self, const char *p_char_array);
-godot_array GDAPI godot_string_bigrams(const godot_string *p_self);
-godot_string GDAPI godot_string_chr(wchar_t p_character);
+godot_packed_string_array GDAPI godot_string_bigrams(const godot_string *p_self);
+godot_string GDAPI godot_string_chr(godot_char_type p_character);
godot_bool GDAPI godot_string_ends_with(const godot_string *p_self, const godot_string *p_string);
-godot_int GDAPI godot_string_count(const godot_string *p_self, godot_string p_what, godot_int p_from, godot_int p_to);
-godot_int GDAPI godot_string_countn(const godot_string *p_self, godot_string p_what, godot_int p_from, godot_int p_to);
-godot_int GDAPI godot_string_find(const godot_string *p_self, godot_string p_what);
-godot_int GDAPI godot_string_find_from(const godot_string *p_self, godot_string p_what, godot_int p_from);
-godot_int GDAPI godot_string_findmk(const godot_string *p_self, const godot_array *p_keys);
-godot_int GDAPI godot_string_findmk_from(const godot_string *p_self, const godot_array *p_keys, godot_int p_from);
-godot_int GDAPI godot_string_findmk_from_in_place(const godot_string *p_self, const godot_array *p_keys, godot_int p_from, godot_int *r_key);
-godot_int GDAPI godot_string_findn(const godot_string *p_self, godot_string p_what);
-godot_int GDAPI godot_string_findn_from(const godot_string *p_self, godot_string p_what, godot_int p_from);
+godot_bool GDAPI godot_string_ends_with_char_array(const godot_string *p_self, const char *p_char_array);
+godot_int GDAPI godot_string_count(const godot_string *p_self, const godot_string *p_what, godot_int p_from, godot_int p_to);
+godot_int GDAPI godot_string_countn(const godot_string *p_self, const godot_string *p_what, godot_int p_from, godot_int p_to);
+godot_int GDAPI godot_string_find(const godot_string *p_self, const godot_string *p_what);
+godot_int GDAPI godot_string_find_from(const godot_string *p_self, const godot_string *p_what, godot_int p_from);
+godot_int GDAPI godot_string_findmk(const godot_string *p_self, const godot_packed_string_array *p_keys);
+godot_int GDAPI godot_string_findmk_from(const godot_string *p_self, const godot_packed_string_array *p_keys, godot_int p_from);
+godot_int GDAPI godot_string_findmk_from_in_place(const godot_string *p_self, const godot_packed_string_array *p_keys, godot_int p_from, godot_int *r_key);
+godot_int GDAPI godot_string_findn(const godot_string *p_self, const godot_string *p_what);
+godot_int GDAPI godot_string_findn_from(const godot_string *p_self, const godot_string *p_what, godot_int p_from);
godot_string GDAPI godot_string_format(const godot_string *p_self, const godot_variant *p_values);
godot_string GDAPI godot_string_format_with_custom_placeholder(const godot_string *p_self, const godot_variant *p_values, const char *p_placeholder);
godot_string GDAPI godot_string_hex_encode_buffer(const uint8_t *p_buffer, godot_int p_len);
godot_int GDAPI godot_string_hex_to_int(const godot_string *p_self);
-godot_int GDAPI godot_string_hex_to_int_without_prefix(const godot_string *p_self);
-godot_string GDAPI godot_string_insert(const godot_string *p_self, godot_int p_at_pos, godot_string p_string);
+godot_int GDAPI godot_string_hex_to_int_with_prefix(const godot_string *p_self);
+godot_string GDAPI godot_string_insert(const godot_string *p_self, godot_int p_at_pos, const godot_string *p_string);
godot_bool GDAPI godot_string_is_numeric(const godot_string *p_self);
godot_bool GDAPI godot_string_is_subsequence_of(const godot_string *p_self, const godot_string *p_string);
godot_bool GDAPI godot_string_is_subsequence_ofi(const godot_string *p_self, const godot_string *p_string);
@@ -133,13 +157,13 @@ godot_string GDAPI godot_string_num_scientific(double p_num);
godot_string GDAPI godot_string_num_with_decimals(double p_num, godot_int p_decimals);
godot_string GDAPI godot_string_pad_decimals(const godot_string *p_self, godot_int p_digits);
godot_string GDAPI godot_string_pad_zeros(const godot_string *p_self, godot_int p_digits);
-godot_string GDAPI godot_string_replace_first(const godot_string *p_self, godot_string p_key, godot_string p_with);
-godot_string GDAPI godot_string_replace(const godot_string *p_self, godot_string p_key, godot_string p_with);
-godot_string GDAPI godot_string_replacen(const godot_string *p_self, godot_string p_key, godot_string p_with);
-godot_int GDAPI godot_string_rfind(const godot_string *p_self, godot_string p_what);
-godot_int GDAPI godot_string_rfindn(const godot_string *p_self, godot_string p_what);
-godot_int GDAPI godot_string_rfind_from(const godot_string *p_self, godot_string p_what, godot_int p_from);
-godot_int GDAPI godot_string_rfindn_from(const godot_string *p_self, godot_string p_what, godot_int p_from);
+godot_string GDAPI godot_string_replace_first(const godot_string *p_self, const godot_string *p_key, const godot_string *p_with);
+godot_string GDAPI godot_string_replace(const godot_string *p_self, const godot_string *p_key, const godot_string *p_with);
+godot_string GDAPI godot_string_replacen(const godot_string *p_self, const godot_string *p_key, const godot_string *p_with);
+godot_int GDAPI godot_string_rfind(const godot_string *p_self, const godot_string *p_what);
+godot_int GDAPI godot_string_rfindn(const godot_string *p_self, const godot_string *p_what);
+godot_int GDAPI godot_string_rfind_from(const godot_string *p_self, const godot_string *p_what, godot_int p_from);
+godot_int GDAPI godot_string_rfindn_from(const godot_string *p_self, const godot_string *p_what, godot_int p_from);
godot_string GDAPI godot_string_rpad(const godot_string *p_self, godot_int p_min_length);
godot_string GDAPI godot_string_rpad_with_custom_character(const godot_string *p_self, godot_int p_min_length, const godot_string *p_character);
godot_real GDAPI godot_string_similarity(const godot_string *p_self, const godot_string *p_string);
@@ -151,64 +175,79 @@ godot_int GDAPI godot_string_to_int(const godot_string *p_self);
godot_string GDAPI godot_string_camelcase_to_underscore(const godot_string *p_self);
godot_string GDAPI godot_string_camelcase_to_underscore_lowercased(const godot_string *p_self);
godot_string GDAPI godot_string_capitalize(const godot_string *p_self);
+
double GDAPI godot_string_char_to_float(const char *p_what);
+double GDAPI godot_string_wchar_to_float(const wchar_t *p_str, const wchar_t **r_end);
+
godot_int GDAPI godot_string_char_to_int(const char *p_what);
-int64_t GDAPI godot_string_wchar_to_int(const wchar_t *p_str);
+godot_int GDAPI godot_string_wchar_to_int(const wchar_t *p_str);
+
godot_int GDAPI godot_string_char_to_int_with_len(const char *p_what, godot_int p_len);
-int64_t GDAPI godot_string_char_to_int64_with_len(const wchar_t *p_str, int p_len);
-int64_t GDAPI godot_string_hex_to_int64(const godot_string *p_self);
-int64_t GDAPI godot_string_hex_to_int64_with_prefix(const godot_string *p_self);
-int64_t GDAPI godot_string_to_int64(const godot_string *p_self);
-double GDAPI godot_string_unicode_char_to_float(const wchar_t *p_str, const wchar_t **r_end);
-
-godot_int GDAPI godot_string_get_slice_count(const godot_string *p_self, godot_string p_splitter);
-godot_string GDAPI godot_string_get_slice(const godot_string *p_self, godot_string p_splitter, godot_int p_slice);
-godot_string GDAPI godot_string_get_slicec(const godot_string *p_self, wchar_t p_splitter, godot_int p_slice);
-
-godot_array GDAPI godot_string_split(const godot_string *p_self, const godot_string *p_splitter);
-godot_array GDAPI godot_string_split_allow_empty(const godot_string *p_self, const godot_string *p_splitter);
-godot_array GDAPI godot_string_split_floats(const godot_string *p_self, const godot_string *p_splitter);
-godot_array GDAPI godot_string_split_floats_allows_empty(const godot_string *p_self, const godot_string *p_splitter);
-godot_array GDAPI godot_string_split_floats_mk(const godot_string *p_self, const godot_array *p_splitters);
-godot_array GDAPI godot_string_split_floats_mk_allows_empty(const godot_string *p_self, const godot_array *p_splitters);
-godot_array GDAPI godot_string_split_ints(const godot_string *p_self, const godot_string *p_splitter);
-godot_array GDAPI godot_string_split_ints_allows_empty(const godot_string *p_self, const godot_string *p_splitter);
-godot_array GDAPI godot_string_split_ints_mk(const godot_string *p_self, const godot_array *p_splitters);
-godot_array GDAPI godot_string_split_ints_mk_allows_empty(const godot_string *p_self, const godot_array *p_splitters);
-godot_array GDAPI godot_string_split_spaces(const godot_string *p_self);
-
-wchar_t GDAPI godot_string_char_lowercase(wchar_t p_char);
-wchar_t GDAPI godot_string_char_uppercase(wchar_t p_char);
+godot_int GDAPI godot_string_wchar_to_int_with_len(const wchar_t *p_str, int p_len);
+
+godot_int GDAPI godot_string_get_slice_count(const godot_string *p_self, const godot_string *p_splitter);
+godot_string GDAPI godot_string_get_slice(const godot_string *p_self, const godot_string *p_splitter, godot_int p_slice);
+godot_string GDAPI godot_string_get_slicec(const godot_string *p_self, godot_char_type p_splitter, godot_int p_slice);
+
+godot_packed_string_array GDAPI godot_string_split(const godot_string *p_self, const godot_string *p_splitter);
+godot_packed_string_array GDAPI godot_string_split_allow_empty(const godot_string *p_self, const godot_string *p_splitter);
+godot_packed_string_array GDAPI godot_string_split_with_maxsplit(const godot_string *p_self, const godot_string *p_splitter, const godot_bool p_allow_empty, const godot_int p_maxsplit);
+
+godot_packed_string_array GDAPI godot_string_rsplit(const godot_string *p_self, const godot_string *p_splitter);
+godot_packed_string_array GDAPI godot_string_rsplit_allow_empty(const godot_string *p_self, const godot_string *p_splitter);
+godot_packed_string_array GDAPI godot_string_rsplit_with_maxsplit(const godot_string *p_self, const godot_string *p_splitter, const godot_bool p_allow_empty, const godot_int p_maxsplit);
+
+godot_packed_float32_array GDAPI godot_string_split_floats(const godot_string *p_self, const godot_string *p_splitter);
+godot_packed_float32_array GDAPI godot_string_split_floats_allow_empty(const godot_string *p_self, const godot_string *p_splitter);
+godot_packed_float32_array GDAPI godot_string_split_floats_mk(const godot_string *p_self, const godot_packed_string_array *p_splitters);
+godot_packed_float32_array GDAPI godot_string_split_floats_mk_allow_empty(const godot_string *p_self, const godot_packed_string_array *p_splitters);
+godot_packed_int32_array GDAPI godot_string_split_ints(const godot_string *p_self, const godot_string *p_splitter);
+godot_packed_int32_array GDAPI godot_string_split_ints_allow_empty(const godot_string *p_self, const godot_string *p_splitter);
+godot_packed_int32_array GDAPI godot_string_split_ints_mk(const godot_string *p_self, const godot_packed_string_array *p_splitters);
+godot_packed_int32_array GDAPI godot_string_split_ints_mk_allow_empty(const godot_string *p_self, const godot_packed_string_array *p_splitters);
+
+godot_packed_string_array GDAPI godot_string_split_spaces(const godot_string *p_self);
+
+godot_char_type GDAPI godot_string_char_lowercase(godot_char_type p_char);
+godot_char_type GDAPI godot_string_char_uppercase(godot_char_type p_char);
godot_string GDAPI godot_string_to_lower(const godot_string *p_self);
godot_string GDAPI godot_string_to_upper(const godot_string *p_self);
godot_string GDAPI godot_string_get_basename(const godot_string *p_self);
godot_string GDAPI godot_string_get_extension(const godot_string *p_self);
godot_string GDAPI godot_string_left(const godot_string *p_self, godot_int p_pos);
-wchar_t GDAPI godot_string_ord_at(const godot_string *p_self, godot_int p_idx);
+godot_char_type GDAPI godot_string_ord_at(const godot_string *p_self, godot_int p_idx);
godot_string GDAPI godot_string_plus_file(const godot_string *p_self, const godot_string *p_file);
godot_string GDAPI godot_string_right(const godot_string *p_self, godot_int p_pos);
+godot_string GDAPI godot_string_repeat(const godot_string *p_self, godot_int p_count);
godot_string GDAPI godot_string_strip_edges(const godot_string *p_self, godot_bool p_left, godot_bool p_right);
godot_string GDAPI godot_string_strip_escapes(const godot_string *p_self);
void GDAPI godot_string_erase(godot_string *p_self, godot_int p_pos, godot_int p_chars);
godot_char_string GDAPI godot_string_ascii(const godot_string *p_self);
-godot_char_string GDAPI godot_string_ascii_extended(const godot_string *p_self);
+godot_char_string GDAPI godot_string_latin1(const godot_string *p_self);
+
godot_char_string GDAPI godot_string_utf8(const godot_string *p_self);
godot_bool GDAPI godot_string_parse_utf8(godot_string *p_self, const char *p_utf8);
godot_bool GDAPI godot_string_parse_utf8_with_len(godot_string *p_self, const char *p_utf8, godot_int p_len);
-godot_string GDAPI godot_string_chars_to_utf8(const char *p_utf8);
-godot_string GDAPI godot_string_chars_to_utf8_with_len(const char *p_utf8, godot_int p_len);
+
+godot_char16_string GDAPI godot_string_utf16(const godot_string *p_self);
+godot_bool GDAPI godot_string_parse_utf16(godot_string *p_self, const char16_t *p_utf16);
+godot_bool GDAPI godot_string_parse_utf16_with_len(godot_string *p_self, const char16_t *p_utf16, godot_int p_len);
uint32_t GDAPI godot_string_hash(const godot_string *p_self);
uint64_t GDAPI godot_string_hash64(const godot_string *p_self);
+
uint32_t GDAPI godot_string_hash_chars(const char *p_cstr);
uint32_t GDAPI godot_string_hash_chars_with_len(const char *p_cstr, godot_int p_len);
-uint32_t GDAPI godot_string_hash_utf8_chars(const wchar_t *p_str);
-uint32_t GDAPI godot_string_hash_utf8_chars_with_len(const wchar_t *p_str, godot_int p_len);
+uint32_t GDAPI godot_string_hash_wide_chars(const wchar_t *p_str);
+uint32_t GDAPI godot_string_hash_wide_chars_with_len(const wchar_t *p_str, godot_int p_len);
+
godot_packed_byte_array GDAPI godot_string_md5_buffer(const godot_string *p_self);
godot_string GDAPI godot_string_md5_text(const godot_string *p_self);
+godot_packed_byte_array GDAPI godot_string_sha1_buffer(const godot_string *p_self);
+godot_string GDAPI godot_string_sha1_text(const godot_string *p_self);
godot_packed_byte_array GDAPI godot_string_sha256_buffer(const godot_string *p_self);
godot_string GDAPI godot_string_sha256_text(const godot_string *p_self);
@@ -231,14 +270,15 @@ godot_string GDAPI godot_string_c_unescape(const godot_string *p_self);
godot_string GDAPI godot_string_http_escape(const godot_string *p_self);
godot_string GDAPI godot_string_http_unescape(const godot_string *p_self);
godot_string GDAPI godot_string_json_escape(const godot_string *p_self);
-godot_string GDAPI godot_string_word_wrap(const godot_string *p_self, godot_int p_chars_per_line);
godot_string GDAPI godot_string_xml_escape(const godot_string *p_self);
godot_string GDAPI godot_string_xml_escape_with_quotes(const godot_string *p_self);
godot_string GDAPI godot_string_xml_unescape(const godot_string *p_self);
godot_string GDAPI godot_string_percent_decode(const godot_string *p_self);
godot_string GDAPI godot_string_percent_encode(const godot_string *p_self);
+godot_string GDAPI godot_string_join(const godot_string *p_self, const godot_packed_string_array *p_parts);
+godot_bool GDAPI godot_string_is_valid_filename(const godot_string *p_self);
godot_bool GDAPI godot_string_is_valid_float(const godot_string *p_self);
godot_bool GDAPI godot_string_is_valid_hex_number(const godot_string *p_self, godot_bool p_with_prefix);
godot_bool GDAPI godot_string_is_valid_html_color(const godot_string *p_self);
@@ -249,8 +289,8 @@ godot_bool GDAPI godot_string_is_valid_ip_address(const godot_string *p_self);
godot_string GDAPI godot_string_dedent(const godot_string *p_self);
godot_string GDAPI godot_string_trim_prefix(const godot_string *p_self, const godot_string *p_prefix);
godot_string GDAPI godot_string_trim_suffix(const godot_string *p_self, const godot_string *p_suffix);
+godot_string GDAPI godot_string_lstrip(const godot_string *p_self, const godot_string *p_chars);
godot_string GDAPI godot_string_rstrip(const godot_string *p_self, const godot_string *p_chars);
-godot_packed_string_array GDAPI godot_string_rsplit(const godot_string *p_self, const godot_string *p_divisor, const godot_bool p_allow_empty, const godot_int p_maxsplit);
void GDAPI godot_string_destroy(godot_string *p_self);
diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp
index 019fa0d1f8..8dbaec4e75 100644
--- a/modules/gdnative/nativescript/api_generator.cpp
+++ b/modules/gdnative/nativescript/api_generator.cpp
@@ -176,10 +176,10 @@ List<ClassAPI> generate_c_api_classes() {
// Register global constants as a fake GlobalConstants singleton class
{
ClassAPI global_constants_api;
- global_constants_api.class_name = L"GlobalConstants";
+ global_constants_api.class_name = "GlobalConstants";
global_constants_api.api_type = ClassDB::API_CORE;
global_constants_api.is_singleton = true;
- global_constants_api.singleton_name = L"GlobalConstants";
+ global_constants_api.singleton_name = "GlobalConstants";
global_constants_api.is_instanciable = false;
const int constants_count = GlobalConstants::get_global_constant_count();
for (int i = 0; i < constants_count; ++i) {
diff --git a/modules/gdscript/SCsub b/modules/gdscript/SCsub
index e58a1d8edc..5c8cbdf869 100644
--- a/modules/gdscript/SCsub
+++ b/modules/gdscript/SCsub
@@ -17,3 +17,7 @@ if env["tools"]:
# Using a define in the disabled case, to avoid having an extra define
# in regular builds where all modules are enabled.
env_gdscript.Append(CPPDEFINES=["GDSCRIPT_NO_LSP"])
+
+if env["tests"]:
+ env_gdscript.Append(CPPDEFINES=["TESTS_ENABLED"])
+ env_gdscript.add_source_files(env.modules_sources, "./tests/*.cpp")
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 9e40a69712..e528fc6623 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -167,6 +167,7 @@
i = ceil(1.45) # i is 2
i = ceil(1.001) # i is 2
[/codeblock]
+ See also [method floor], [method round], and [method stepify].
</description>
</method>
<method name="char">
@@ -338,6 +339,7 @@
# a is -3.0
a = floor(-2.99)
[/codeblock]
+ See also [method ceil], [method round], and [method stepify].
[b]Note:[/b] This method returns a float. If you need an integer, you can use [code]int(s)[/code] directly.
</description>
</method>
@@ -1043,6 +1045,7 @@
[codeblock]
round(2.6) # Returns 3
[/codeblock]
+ See also [method floor], [method ceil], and [method stepify].
</description>
</method>
<method name="seed">
@@ -1161,6 +1164,7 @@
stepify(100, 32) # Returns 96
stepify(3.14159, 0.01) # Returns 3.14
[/codeblock]
+ See also [method ceil], [method floor], and [method round].
</description>
</method>
<method name="str" qualifiers="vararg">
diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml
index 62ccb93901..631a102130 100644
--- a/modules/gdscript/doc_classes/GDScript.xml
+++ b/modules/gdscript/doc_classes/GDScript.xml
@@ -8,7 +8,7 @@
[method new] creates a new instance of the script. [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/index.html</link>
+ <link title="GDScript tutorial index">https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/index.html</link>
</tutorials>
<methods>
<method name="get_as_byte_code" qualifiers="const">
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index ae1f2893f1..9a3273d201 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -33,15 +33,15 @@
#include "../gdscript_tokenizer.h"
#include "editor/editor_settings.h"
-static bool _is_char(CharType c) {
+static bool _is_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
}
-static bool _is_hex_symbol(CharType c) {
+static bool _is_hex_symbol(char32_t c) {
return ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
}
-static bool _is_bin_symbol(CharType c) {
+static bool _is_bin_symbol(char32_t c) {
return (c == '0' || c == '1');
}
@@ -119,7 +119,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line)
/* search the line */
bool match = true;
- const CharType *start_key = color_regions[c].start_key.c_str();
+ const char32_t *start_key = color_regions[c].start_key.get_data();
for (int k = 0; k < start_key_length; k++) {
if (start_key[k] != str[from + k]) {
match = false;
@@ -153,18 +153,16 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line)
/* if we are in one find the end key */
if (in_region != -1) {
- /* check there is enough room */
- int chars_left = line_length - from;
- int end_key_length = color_regions[in_region].end_key.length();
- if (chars_left < end_key_length) {
- continue;
- }
-
/* search the line */
int region_end_index = -1;
- const CharType *end_key = color_regions[in_region].start_key.c_str();
+ int end_key_length = color_regions[in_region].end_key.length();
+ const char32_t *end_key = color_regions[in_region].end_key.get_data();
for (; from < line_length; from++) {
- if (!is_a_symbol) {
+ if (line_length - from < end_key_length) {
+ break;
+ }
+
+ if (!is_symbol(str[from])) {
continue;
}
@@ -173,9 +171,10 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line)
continue;
}
+ region_end_index = from;
for (int k = 0; k < end_key_length; k++) {
- if (end_key[k] == str[from + k]) {
- region_end_index = from;
+ if (end_key[k] != str[from + k]) {
+ region_end_index = -1;
break;
}
}
@@ -192,7 +191,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line)
previous_type = REGION;
previous_text = "";
previous_column = j;
- j = from;
+ j = from + (end_key_length - 1);
if (region_end_index == -1) {
color_region_cache[p_line] = in_region;
}
@@ -572,8 +571,12 @@ void GDScriptSyntaxHighlighter::add_color_region(const String &p_start_key, cons
}
}
+ int at = 0;
for (int i = 0; i < color_regions.size(); i++) {
ERR_FAIL_COND_MSG(color_regions[i].start_key == p_start_key, "color region with start key '" + p_start_key + "' already exists.");
+ if (p_start_key.length() < color_regions[i].start_key.length()) {
+ at++;
+ }
}
ColorRegion color_region;
@@ -581,7 +584,8 @@ void GDScriptSyntaxHighlighter::add_color_region(const String &p_start_key, cons
color_region.start_key = p_start_key;
color_region.end_key = p_end_key;
color_region.line_only = p_line_only;
- color_regions.push_back(color_region);
+ color_regions.insert(at, color_region);
+ clear_highlighting_cache();
}
Ref<EditorSyntaxHighlighter> GDScriptSyntaxHighlighter::_create() const {
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 541d46a2af..0263e32c5b 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -603,10 +603,8 @@ Error GDScript::reload(bool p_keep_state) {
}
if (!source_path.empty()) {
MutexLock lock(GDScriptCache::singleton->lock);
- Ref<GDScript> self(this);
if (!GDScriptCache::singleton->shallow_gdscript_cache.has(source_path)) {
- GDScriptCache::singleton->shallow_gdscript_cache[source_path] = self;
- self->unreference();
+ GDScriptCache::singleton->shallow_gdscript_cache[source_path] = this;
}
}
}
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 9906b4014d..79317ff846 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -69,6 +69,7 @@ class GDScript : public Script {
friend class GDScriptInstance;
friend class GDScriptFunction;
+ friend class GDScriptAnalyzer;
friend class GDScriptCompiler;
friend class GDScriptFunctions;
friend class GDScriptLanguage;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 3253c8e945..8fbc5bcb25 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -182,7 +182,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
return ERR_PARSE_ERROR;
}
- Error err = parser->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
+ Error err = parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
if (err != OK) {
push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", p_class->extends_path), p_class);
return err;
@@ -208,11 +208,12 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
return ERR_PARSE_ERROR;
}
- Error err = parser->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
+ Error err = parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
if (err != OK) {
push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), p_class);
return err;
}
+ base = parser->get_parser()->head->get_datatype();
}
} else if (ProjectSettings::get_singleton()->has_autoload(name) && ProjectSettings::get_singleton()->get_autoload(name).is_singleton) {
const ProjectSettings::AutoloadInfo &info = ProjectSettings::get_singleton()->get_autoload(name);
@@ -227,7 +228,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
return ERR_PARSE_ERROR;
}
- Error err = parser->raise_status(GDScriptParserRef::INHERITANCE_SOLVED);
+ Error err = parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
if (err != OK) {
push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), p_class);
return err;
@@ -302,6 +303,16 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
return ERR_PARSE_ERROR;
}
+ // Check for cyclic inheritance.
+ const GDScriptParser::ClassNode *base_class = result.class_type;
+ while (base_class) {
+ if (base_class->fqcn == p_class->fqcn) {
+ push_error("Cyclic inheritance.", p_class);
+ return ERR_PARSE_ERROR;
+ }
+ base_class = base_class->base_type.class_type;
+ }
+
p_class->base_type = result;
class_type.native_type = result.native_type;
p_class->set_datatype(class_type);
@@ -309,7 +320,10 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
if (p_recursive) {
for (int i = 0; i < p_class->members.size(); i++) {
if (p_class->members[i].type == GDScriptParser::ClassNode::Member::CLASS) {
- resolve_inheritance(p_class->members[i].m_class, true);
+ Error err = resolve_inheritance(p_class->members[i].m_class, true);
+ if (err) {
+ return err;
+ }
}
}
}
@@ -491,6 +505,9 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
member.variable->set_datatype(datatype); // Allow recursive usage.
reduce_expression(member.variable->initializer);
datatype = member.variable->initializer->get_datatype();
+ if (datatype.type_source != GDScriptParser::DataType::UNDETECTED) {
+ datatype.type_source = GDScriptParser::DataType::INFERRED;
+ }
}
if (member.variable->datatype_specifier != nullptr) {
@@ -526,6 +543,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
} else if (datatype.builtin_type == Variant::NIL) {
push_error(vformat(R"(Cannot infer the type of "%s" variable because the initial value is "null".)", member.variable->identifier->name), member.variable->initializer);
}
+ datatype.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
}
datatype.is_constant = false;
@@ -776,7 +794,7 @@ void GDScriptAnalyzer::resolve_node(GDScriptParser::Node *p_node) {
resolve_match_branch(static_cast<GDScriptParser::MatchBranchNode *>(p_node), nullptr);
break;
case GDScriptParser::Node::PARAMETER:
- resolve_pararameter(static_cast<GDScriptParser::ParameterNode *>(p_node));
+ resolve_parameter(static_cast<GDScriptParser::ParameterNode *>(p_node));
break;
case GDScriptParser::Node::PATTERN:
resolve_match_pattern(static_cast<GDScriptParser::PatternNode *>(p_node), nullptr);
@@ -830,7 +848,7 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
parser->current_function = p_function;
for (int i = 0; i < p_function->parameters.size(); i++) {
- resolve_pararameter(p_function->parameters[i]);
+ resolve_parameter(p_function->parameters[i]);
#ifdef DEBUG_ENABLED
if (p_function->parameters[i]->usages == 0 && !String(p_function->parameters[i]->identifier->name).begins_with("_")) {
parser->push_warning(p_function->parameters[i]->identifier, GDScriptWarning::UNUSED_PARAMETER, p_function->identifier->name, p_function->parameters[i]->identifier->name);
@@ -900,6 +918,7 @@ void GDScriptAnalyzer::decide_suite_type(GDScriptParser::Node *p_suite, GDScript
p_suite->datatype.type_source = GDScriptParser::DataType::UNDETECTED;
} else {
p_suite->set_datatype(p_statement->get_datatype());
+ p_suite->datatype.type_source = GDScriptParser::DataType::INFERRED;
}
break;
default:
@@ -1245,14 +1264,19 @@ void GDScriptAnalyzer::resolve_match_pattern(GDScriptParser::PatternNode *p_matc
p_match_pattern->set_datatype(result);
}
-void GDScriptAnalyzer::resolve_pararameter(GDScriptParser::ParameterNode *p_parameter) {
+void GDScriptAnalyzer::resolve_parameter(GDScriptParser::ParameterNode *p_parameter) {
GDScriptParser::DataType result;
result.kind = GDScriptParser::DataType::VARIANT;
if (p_parameter->default_value != nullptr) {
reduce_expression(p_parameter->default_value);
result = p_parameter->default_value->get_datatype();
- result.type_source = GDScriptParser::DataType::INFERRED;
+ if (p_parameter->infer_datatype) {
+ result.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
+ } else {
+ result.type_source = GDScriptParser::DataType::INFERRED;
+ }
+ result.is_constant = false;
}
if (p_parameter->datatype_specifier != nullptr) {
@@ -1442,7 +1466,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
bool compatible = true;
GDScriptParser::DataType op_type = p_assignment->assigned_value->get_datatype();
if (p_assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
- op_type = get_operation_type(p_assignment->variant_op, p_assignment->assignee->get_datatype(), p_assignment->assigned_value->get_datatype(), compatible);
+ op_type = get_operation_type(p_assignment->variant_op, p_assignment->assignee->get_datatype(), p_assignment->assigned_value->get_datatype(), compatible, p_assignment->assigned_value);
}
if (compatible) {
@@ -1605,7 +1629,7 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o
ERR_PRINT("Parser bug: unknown binary operation.");
}
}
- p_binary_op->set_datatype(type_from_variant(p_binary_op->reduced_value));
+ p_binary_op->set_datatype(type_from_variant(p_binary_op->reduced_value, p_binary_op));
return;
}
@@ -1619,7 +1643,7 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o
} else {
if (p_binary_op->variant_op < Variant::OP_MAX) {
bool valid = false;
- result = get_operation_type(p_binary_op->variant_op, p_binary_op->left_operand->get_datatype(), right_type, valid);
+ result = get_operation_type(p_binary_op->variant_op, p_binary_op->left_operand->get_datatype(), right_type, valid, p_binary_op);
if (!valid) {
push_error(vformat(R"(Invalid operands "%s" and "%s" for "%s" operator.)", p_binary_op->left_operand->get_datatype().to_string(), right_type.to_string(), Variant::get_operator_name(p_binary_op->variant_op)), p_binary_op);
@@ -2048,7 +2072,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
if (valid) {
p_identifier->is_constant = true;
p_identifier->reduced_value = result;
- p_identifier->set_datatype(type_from_variant(result));
+ p_identifier->set_datatype(type_from_variant(result, p_identifier));
} else {
push_error(vformat(R"(Cannot find constant "%s" on type "%s".)", name, base.to_string()), p_identifier);
}
@@ -2179,7 +2203,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
if (valid) {
p_identifier->is_constant = true;
p_identifier->reduced_value = int_constant;
- p_identifier->set_datatype(type_from_variant(int_constant));
+ p_identifier->set_datatype(type_from_variant(int_constant, p_identifier));
return;
}
}
@@ -2276,10 +2300,34 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
return;
}
+ // Try singletons.
+ // Do this before globals because this might be a singleton loading another one before it's compiled.
+ if (ProjectSettings::get_singleton()->has_autoload(name)) {
+ const ProjectSettings::AutoloadInfo &autoload = ProjectSettings::get_singleton()->get_autoload(name);
+ if (autoload.is_singleton) {
+ // Singleton exists, so it's at least a Node.
+ GDScriptParser::DataType result;
+ result.kind = GDScriptParser::DataType::NATIVE;
+ result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
+ if (autoload.path.to_lower().ends_with(GDScriptLanguage::get_singleton()->get_extension())) {
+ Ref<GDScriptParserRef> parser = get_parser_for(autoload.path);
+ if (parser.is_valid()) {
+ Error err = parser->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+ if (err == OK) {
+ result = type_from_metatype(parser->get_parser()->head->get_datatype());
+ }
+ }
+ }
+ result.is_constant = true;
+ p_identifier->set_datatype(result);
+ return;
+ }
+ }
+
if (GDScriptLanguage::get_singleton()->get_global_map().has(name)) {
int idx = GDScriptLanguage::get_singleton()->get_global_map()[name];
Variant constant = GDScriptLanguage::get_singleton()->get_global_array()[idx];
- p_identifier->set_datatype(type_from_variant(constant));
+ p_identifier->set_datatype(type_from_variant(constant, p_identifier));
p_identifier->is_constant = true;
p_identifier->reduced_value = constant;
return;
@@ -2287,7 +2335,7 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(name)) {
Variant constant = GDScriptLanguage::get_singleton()->get_named_globals_map()[name];
- p_identifier->set_datatype(type_from_variant(constant));
+ p_identifier->set_datatype(type_from_variant(constant, p_identifier));
p_identifier->is_constant = true;
p_identifier->reduced_value = constant;
return;
@@ -2309,7 +2357,7 @@ void GDScriptAnalyzer::reduce_literal(GDScriptParser::LiteralNode *p_literal) {
p_literal->reduced_value = p_literal->value;
p_literal->is_constant = true;
- p_literal->set_datatype(type_from_variant(p_literal->reduced_value));
+ p_literal->set_datatype(type_from_variant(p_literal->reduced_value, p_literal));
}
void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
@@ -2346,7 +2394,7 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
p_preload->is_constant = true;
p_preload->reduced_value = p_preload->resource;
- p_preload->set_datatype(type_from_variant(p_preload->reduced_value));
+ p_preload->set_datatype(type_from_variant(p_preload->reduced_value, p_preload));
}
void GDScriptAnalyzer::reduce_self(GDScriptParser::SelfNode *p_self) {
@@ -2395,7 +2443,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
} else {
p_subscript->is_constant = true;
p_subscript->reduced_value = value;
- result_type = type_from_variant(value);
+ result_type = type_from_variant(value, p_subscript);
}
result_type.kind = GDScriptParser::DataType::VARIANT;
} else {
@@ -2435,7 +2483,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
} else {
p_subscript->is_constant = true;
p_subscript->reduced_value = value;
- result_type = type_from_variant(value);
+ result_type = type_from_variant(value, p_subscript);
}
result_type.kind = GDScriptParser::DataType::VARIANT;
} else {
@@ -2659,13 +2707,13 @@ void GDScriptAnalyzer::reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op)
if (p_unary_op->operand->is_constant) {
p_unary_op->is_constant = true;
p_unary_op->reduced_value = Variant::evaluate(p_unary_op->variant_op, p_unary_op->operand->reduced_value, Variant());
- result = type_from_variant(p_unary_op->reduced_value);
+ result = type_from_variant(p_unary_op->reduced_value, p_unary_op);
} else if (p_unary_op->operand->get_datatype().is_variant()) {
result.kind = GDScriptParser::DataType::VARIANT;
mark_node_unsafe(p_unary_op);
} else {
bool valid = false;
- result = get_operation_type(p_unary_op->variant_op, p_unary_op->operand->get_datatype(), p_unary_op->operand->get_datatype(), valid);
+ result = get_operation_type(p_unary_op->variant_op, p_unary_op->operand->get_datatype(), p_unary_op->operand->get_datatype(), valid, p_unary_op);
if (!valid) {
push_error(vformat(R"(Invalid operand of type "%s" for unary operator "%s".)", p_unary_op->operand->get_datatype().to_string(), Variant::get_operator_name(p_unary_op->variant_op)), p_unary_op->operand);
@@ -2675,7 +2723,7 @@ void GDScriptAnalyzer::reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op)
p_unary_op->set_datatype(result);
}
-GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_value) {
+GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source) {
GDScriptParser::DataType result;
result.is_constant = true;
result.kind = GDScriptParser::DataType::BUILTIN;
@@ -2697,19 +2745,44 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va
scr = obj->get_script();
}
if (scr.is_valid()) {
- result.script_type = scr;
- result.script_path = scr->get_path();
- Ref<GDScript> gds = scr;
- if (gds.is_valid()) {
- result.kind = GDScriptParser::DataType::CLASS;
- Ref<GDScriptParserRef> ref = get_parser_for(gds->get_path());
- ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
- result.class_type = ref->get_parser()->head;
- result.script_path = ref->get_parser()->script_path;
+ if (scr->is_valid()) {
+ result.script_type = scr;
+ result.script_path = scr->get_path();
+ Ref<GDScript> gds = scr;
+ if (gds.is_valid()) {
+ result.kind = GDScriptParser::DataType::CLASS;
+ // This might be an inner class, so we want to get the parser for the root.
+ // But still get the inner class from that tree.
+ GDScript *current = gds.ptr();
+ List<StringName> class_chain;
+ while (current->_owner) {
+ // Push to front so it's in reverse.
+ class_chain.push_front(current->name);
+ current = current->_owner;
+ }
+
+ Ref<GDScriptParserRef> ref = get_parser_for(current->path);
+ ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
+
+ GDScriptParser::ClassNode *found = ref->get_parser()->head;
+
+ // It should be okay to assume this exists, since we have a complete script already.
+ for (const List<StringName>::Element *E = class_chain.front(); E; E = E->next()) {
+ found = found->get_member(E->get()).m_class;
+ }
+
+ result.class_type = found;
+ result.script_path = ref->get_parser()->script_path;
+ } else {
+ result.kind = GDScriptParser::DataType::SCRIPT;
+ }
+ result.native_type = scr->get_instance_base_type();
} else {
- result.kind = GDScriptParser::DataType::SCRIPT;
+ push_error(vformat(R"(Constant value uses script from "%s" which is loaded but not compiled.)", scr->get_path()), p_source);
+ result.kind = GDScriptParser::DataType::VARIANT;
+ result.type_source = GDScriptParser::DataType::UNDETECTED;
+ result.is_meta_type = false;
}
- result.native_type = scr->get_instance_base_type();
} else {
result.kind = GDScriptParser::DataType::NATIVE;
if (result.native_type == GDScriptNativeClass::get_class_static()) {
@@ -2900,7 +2973,7 @@ bool GDScriptAnalyzer::validate_call_arg(const List<GDScriptParser::DataType> &p
if (arg_type.is_variant()) {
// Argument can be anything, so this is unsafe.
mark_node_unsafe(p_call->arguments[i]);
- } else if (!is_type_compatible(par_type, arg_type, true)) {
+ } else if (par_type.is_hard_type() && !is_type_compatible(par_type, arg_type, true)) {
// Supertypes are acceptable for dynamic compliance, but it's unsafe.
mark_node_unsafe(p_call);
if (!is_type_compatible(arg_type, par_type)) {
@@ -2965,7 +3038,7 @@ bool GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, con
}
#endif
-GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, const GDScriptParser::DataType &p_b, bool &r_valid) {
+GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, const GDScriptParser::DataType &p_b, bool &r_valid, const GDScriptParser::Node *p_source) {
// This function creates dummy variant values and apply the operation to those. Less error-prone than keeping a table of valid operations.
GDScriptParser::DataType result;
@@ -3038,7 +3111,7 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator
Variant::evaluate(p_operation, a, b, ret, r_valid);
if (r_valid) {
- return type_from_variant(ret);
+ return type_from_variant(ret, p_source);
}
return result;
@@ -3236,6 +3309,9 @@ Error GDScriptAnalyzer::resolve_program() {
List<String> parser_keys;
depended_parsers.get_key_list(&parser_keys);
for (const List<String>::Element *E = parser_keys.front(); E != nullptr; E = E->next()) {
+ if (depended_parsers[E->get()].is_null()) {
+ return ERR_PARSE_ERROR;
+ }
depended_parsers[E->get()]->raise_status(GDScriptParserRef::FULLY_SOLVED);
}
depended_parsers.clear();
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index da767522ad..c3911cce76 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -67,7 +67,7 @@ class GDScriptAnalyzer {
void resolve_match(GDScriptParser::MatchNode *p_match);
void resolve_match_branch(GDScriptParser::MatchBranchNode *p_match_branch, GDScriptParser::ExpressionNode *p_match_test);
void resolve_match_pattern(GDScriptParser::PatternNode *p_match_pattern, GDScriptParser::ExpressionNode *p_match_test);
- void resolve_pararameter(GDScriptParser::ParameterNode *p_parameter);
+ void resolve_parameter(GDScriptParser::ParameterNode *p_parameter);
void resolve_return(GDScriptParser::ReturnNode *p_return);
// Reduction functions.
@@ -90,7 +90,7 @@ class GDScriptAnalyzer {
void reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op);
// Helpers.
- GDScriptParser::DataType type_from_variant(const Variant &p_value);
+ GDScriptParser::DataType type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source);
GDScriptParser::DataType type_from_metatype(const GDScriptParser::DataType &p_meta_type) const;
GDScriptParser::DataType type_from_property(const PropertyInfo &p_property) const;
GDScriptParser::DataType make_global_class_meta_type(const StringName &p_class_name);
@@ -98,7 +98,7 @@ class GDScriptAnalyzer {
bool function_signature_from_info(const MethodInfo &p_info, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg);
bool validate_call_arg(const List<GDScriptParser::DataType> &p_par_types, int p_default_args_count, bool p_is_vararg, const GDScriptParser::CallNode *p_call);
bool validate_call_arg(const MethodInfo &p_method, const GDScriptParser::CallNode *p_call);
- GDScriptParser::DataType get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, const GDScriptParser::DataType &p_b, bool &r_valid);
+ GDScriptParser::DataType get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, const GDScriptParser::DataType &p_b, bool &r_valid, const GDScriptParser::Node *p_source);
bool is_type_compatible(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion = false) const;
void push_error(const String &p_message, const GDScriptParser::Node *p_origin);
void mark_node_unsafe(const GDScriptParser::Node *p_node);
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
new file mode 100644
index 0000000000..8f0ce99de6
--- /dev/null
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -0,0 +1,736 @@
+/*************************************************************************/
+/* gdscript_byte_codegen.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gdscript_byte_codegen.h"
+
+#include "core/debugger/engine_debugger.h"
+#include "gdscript.h"
+
+uint32_t GDScriptByteCodeGenerator::add_parameter(const StringName &p_name, bool p_is_optional, const GDScriptDataType &p_type) {
+#ifdef TOOLS_ENABLED
+ function->arg_names.push_back(p_name);
+#endif
+ function->_argument_count++;
+ function->argument_types.push_back(p_type);
+ if (p_is_optional) {
+ if (function->_default_arg_count == 0) {
+ append(GDScriptFunction::OPCODE_JUMP_TO_DEF_ARGUMENT);
+ }
+ function->default_arguments.push_back(opcodes.size());
+ function->_default_arg_count++;
+ }
+
+ return add_local(p_name, p_type);
+}
+
+uint32_t GDScriptByteCodeGenerator::add_local(const StringName &p_name, const GDScriptDataType &p_type) {
+ int stack_pos = increase_stack();
+ add_stack_identifier(p_name, stack_pos);
+ return stack_pos;
+}
+
+uint32_t GDScriptByteCodeGenerator::add_local_constant(const StringName &p_name, const Variant &p_constant) {
+ int index = add_or_get_constant(p_constant);
+ local_constants[p_name] = index;
+ return index;
+}
+
+uint32_t GDScriptByteCodeGenerator::add_or_get_constant(const Variant &p_constant) {
+ if (constant_map.has(p_constant)) {
+ return constant_map[p_constant];
+ }
+ int index = constant_map.size();
+ constant_map[p_constant] = index;
+ return index;
+}
+
+uint32_t GDScriptByteCodeGenerator::add_or_get_name(const StringName &p_name) {
+ return get_name_map_pos(p_name);
+}
+
+uint32_t GDScriptByteCodeGenerator::add_temporary() {
+ current_temporaries++;
+ return increase_stack();
+}
+
+void GDScriptByteCodeGenerator::pop_temporary() {
+ current_stack_size--;
+ current_temporaries--;
+}
+
+void GDScriptByteCodeGenerator::start_parameters() {}
+
+void GDScriptByteCodeGenerator::end_parameters() {
+ function->default_arguments.invert();
+}
+
+void GDScriptByteCodeGenerator::write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCMode p_rpc_mode, const GDScriptDataType &p_return_type) {
+ function = memnew(GDScriptFunction);
+ debug_stack = EngineDebugger::is_active();
+
+ function->name = p_function_name;
+ function->_script = p_script;
+ function->source = p_script->get_path();
+
+#ifdef DEBUG_ENABLED
+ function->func_cname = (String(function->source) + " - " + String(p_function_name)).utf8();
+ function->_func_cname = function->func_cname.get_data();
+#endif
+
+ function->_static = p_static;
+ function->return_type = p_return_type;
+ function->rpc_mode = p_rpc_mode;
+ function->_argument_count = 0;
+}
+
+GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
+ append(GDScriptFunction::OPCODE_END);
+
+ if (constant_map.size()) {
+ function->_constant_count = constant_map.size();
+ function->constants.resize(constant_map.size());
+ function->_constants_ptr = function->constants.ptrw();
+ const Variant *K = nullptr;
+ while ((K = constant_map.next(K))) {
+ int idx = constant_map[*K];
+ function->constants.write[idx] = *K;
+ }
+ } else {
+ function->_constants_ptr = nullptr;
+ function->_constant_count = 0;
+ }
+
+ if (name_map.size()) {
+ function->global_names.resize(name_map.size());
+ function->_global_names_ptr = &function->global_names[0];
+ for (Map<StringName, int>::Element *E = name_map.front(); E; E = E->next()) {
+ function->global_names.write[E->get()] = E->key();
+ }
+ function->_global_names_count = function->global_names.size();
+
+ } else {
+ function->_global_names_ptr = nullptr;
+ function->_global_names_count = 0;
+ }
+
+ if (opcodes.size()) {
+ function->code = opcodes;
+ function->_code_ptr = &function->code[0];
+ function->_code_size = opcodes.size();
+
+ } else {
+ function->_code_ptr = nullptr;
+ function->_code_size = 0;
+ }
+
+ if (function->default_arguments.size()) {
+ function->_default_arg_count = function->default_arguments.size();
+ function->_default_arg_ptr = &function->default_arguments[0];
+ } else {
+ function->_default_arg_count = 0;
+ function->_default_arg_ptr = nullptr;
+ }
+
+ if (debug_stack) {
+ function->stack_debug = stack_debug;
+ }
+ function->_stack_size = stack_max;
+ function->_call_size = call_max;
+
+ ended = true;
+ return function;
+}
+
+#ifdef DEBUG_ENABLED
+void GDScriptByteCodeGenerator::set_signature(const String &p_signature) {
+ function->profile.signature = p_signature;
+}
+#endif
+
+void GDScriptByteCodeGenerator::set_initial_line(int p_line) {
+ function->_initial_line = p_line;
+}
+
+void GDScriptByteCodeGenerator::write_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) {
+ append(GDScriptFunction::OPCODE_OPERATOR);
+ append(p_operator);
+ append(p_left_operand);
+ append(p_right_operand);
+ append(p_target);
+}
+
+void GDScriptByteCodeGenerator::write_type_test(const Address &p_target, const Address &p_source, const Address &p_type) {
+ append(GDScriptFunction::OPCODE_EXTENDS_TEST);
+ append(p_source);
+ append(p_type);
+ append(p_target);
+}
+
+void GDScriptByteCodeGenerator::write_type_test_builtin(const Address &p_target, const Address &p_source, Variant::Type p_type) {
+ append(GDScriptFunction::OPCODE_IS_BUILTIN);
+ append(p_source);
+ append(p_type);
+ append(p_target);
+}
+
+void GDScriptByteCodeGenerator::write_and_left_operand(const Address &p_left_operand) {
+ append(GDScriptFunction::OPCODE_JUMP_IF_NOT);
+ append(p_left_operand);
+ logic_op_jump_pos1.push_back(opcodes.size());
+ append(0); // Jump target, will be patched.
+}
+
+void GDScriptByteCodeGenerator::write_and_right_operand(const Address &p_right_operand) {
+ append(GDScriptFunction::OPCODE_JUMP_IF_NOT);
+ append(p_right_operand);
+ logic_op_jump_pos2.push_back(opcodes.size());
+ append(0); // Jump target, will be patched.
+}
+
+void GDScriptByteCodeGenerator::write_end_and(const Address &p_target) {
+ // If here means both operands are true.
+ append(GDScriptFunction::OPCODE_ASSIGN_TRUE);
+ append(p_target);
+ // Jump away from the fail condition.
+ append(GDScriptFunction::OPCODE_JUMP);
+ append(opcodes.size() + 3);
+ // Here it means one of operands is false.
+ patch_jump(logic_op_jump_pos1.back()->get());
+ patch_jump(logic_op_jump_pos2.back()->get());
+ logic_op_jump_pos1.pop_back();
+ logic_op_jump_pos2.pop_back();
+ append(GDScriptFunction::OPCODE_ASSIGN_FALSE);
+ append(p_target);
+}
+
+void GDScriptByteCodeGenerator::write_or_left_operand(const Address &p_left_operand) {
+ append(GDScriptFunction::OPCODE_JUMP_IF);
+ append(p_left_operand);
+ logic_op_jump_pos1.push_back(opcodes.size());
+ append(0); // Jump target, will be patched.
+}
+
+void GDScriptByteCodeGenerator::write_or_right_operand(const Address &p_right_operand) {
+ append(GDScriptFunction::OPCODE_JUMP_IF);
+ append(p_right_operand);
+ logic_op_jump_pos2.push_back(opcodes.size());
+ append(0); // Jump target, will be patched.
+}
+
+void GDScriptByteCodeGenerator::write_end_or(const Address &p_target) {
+ // If here means both operands are false.
+ append(GDScriptFunction::OPCODE_ASSIGN_FALSE);
+ append(p_target);
+ // Jump away from the success condition.
+ append(GDScriptFunction::OPCODE_JUMP);
+ append(opcodes.size() + 3);
+ // Here it means one of operands is false.
+ patch_jump(logic_op_jump_pos1.back()->get());
+ patch_jump(logic_op_jump_pos2.back()->get());
+ logic_op_jump_pos1.pop_back();
+ logic_op_jump_pos2.pop_back();
+ append(GDScriptFunction::OPCODE_ASSIGN_TRUE);
+ append(p_target);
+}
+
+void GDScriptByteCodeGenerator::write_start_ternary(const Address &p_target) {
+ ternary_result.push_back(p_target);
+}
+
+void GDScriptByteCodeGenerator::write_ternary_condition(const Address &p_condition) {
+ append(GDScriptFunction::OPCODE_JUMP_IF_NOT);
+ append(p_condition);
+ ternary_jump_fail_pos.push_back(opcodes.size());
+ append(0); // Jump target, will be patched.
+}
+
+void GDScriptByteCodeGenerator::write_ternary_true_expr(const Address &p_expr) {
+ append(GDScriptFunction::OPCODE_ASSIGN);
+ append(ternary_result.back()->get());
+ append(p_expr);
+ // Jump away from the false path.
+ append(GDScriptFunction::OPCODE_JUMP);
+ ternary_jump_skip_pos.push_back(opcodes.size());
+ append(0);
+ // Fail must jump here.
+ patch_jump(ternary_jump_fail_pos.back()->get());
+ ternary_jump_fail_pos.pop_back();
+}
+
+void GDScriptByteCodeGenerator::write_ternary_false_expr(const Address &p_expr) {
+ append(GDScriptFunction::OPCODE_ASSIGN);
+ append(ternary_result.back()->get());
+ append(p_expr);
+}
+
+void GDScriptByteCodeGenerator::write_end_ternary() {
+ patch_jump(ternary_jump_skip_pos.back()->get());
+ ternary_jump_skip_pos.pop_back();
+}
+
+void GDScriptByteCodeGenerator::write_set(const Address &p_target, const Address &p_index, const Address &p_source) {
+ append(GDScriptFunction::OPCODE_SET);
+ append(p_target);
+ append(p_index);
+ append(p_source);
+}
+
+void GDScriptByteCodeGenerator::write_get(const Address &p_target, const Address &p_index, const Address &p_source) {
+ append(GDScriptFunction::OPCODE_GET);
+ append(p_source);
+ append(p_index);
+ append(p_target);
+}
+
+void GDScriptByteCodeGenerator::write_set_named(const Address &p_target, const StringName &p_name, const Address &p_source) {
+ append(GDScriptFunction::OPCODE_SET_NAMED);
+ append(p_target);
+ append(p_name);
+ append(p_source);
+}
+
+void GDScriptByteCodeGenerator::write_get_named(const Address &p_target, const StringName &p_name, const Address &p_source) {
+ append(GDScriptFunction::OPCODE_GET_NAMED);
+ append(p_source);
+ append(p_name);
+ append(p_target);
+}
+
+void GDScriptByteCodeGenerator::write_set_member(const Address &p_value, const StringName &p_name) {
+ append(GDScriptFunction::OPCODE_SET_MEMBER);
+ append(p_name);
+ append(p_value);
+}
+
+void GDScriptByteCodeGenerator::write_get_member(const Address &p_target, const StringName &p_name) {
+ append(GDScriptFunction::OPCODE_GET_MEMBER);
+ append(p_name);
+ append(p_target);
+}
+
+void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Address &p_source) {
+ if (p_target.type.has_type && !p_source.type.has_type) {
+ // Typed assignment.
+ switch (p_target.type.kind) {
+ case GDScriptDataType::BUILTIN: {
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN);
+ append(p_target.type.builtin_type);
+ append(p_target);
+ append(p_source);
+ } break;
+ case GDScriptDataType::NATIVE: {
+ int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_target.type.native_type];
+ class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS);
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_NATIVE);
+ append(class_idx);
+ append(p_target);
+ append(p_source);
+ } break;
+ case GDScriptDataType::SCRIPT:
+ case GDScriptDataType::GDSCRIPT: {
+ Variant script = p_target.type.script_type;
+ int idx = get_constant_pos(script);
+
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT);
+ append(idx);
+ append(p_target);
+ append(p_source);
+ } break;
+ default: {
+ ERR_PRINT("Compiler bug: unresolved assign.");
+
+ // Shouldn't get here, but fail-safe to a regular assignment
+ append(GDScriptFunction::OPCODE_ASSIGN);
+ append(p_target);
+ append(p_source);
+ }
+ }
+ } else {
+ if (p_target.type.kind == GDScriptDataType::BUILTIN && p_source.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type != p_source.type.builtin_type) {
+ // Need conversion..
+ append(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN);
+ append(p_target.type.builtin_type);
+ append(p_target);
+ append(p_source);
+ } else {
+ // Either untyped assignment or already type-checked by the parser
+ append(GDScriptFunction::OPCODE_ASSIGN);
+ append(p_target);
+ append(p_source);
+ }
+ }
+}
+
+void GDScriptByteCodeGenerator::write_assign_true(const Address &p_target) {
+ append(GDScriptFunction::OPCODE_ASSIGN_TRUE);
+ append(p_target);
+}
+
+void GDScriptByteCodeGenerator::write_assign_false(const Address &p_target) {
+ append(GDScriptFunction::OPCODE_ASSIGN_FALSE);
+ append(p_target);
+}
+
+void GDScriptByteCodeGenerator::write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) {
+ switch (p_type.kind) {
+ case GDScriptDataType::BUILTIN: {
+ append(GDScriptFunction::OPCODE_CAST_TO_BUILTIN);
+ append(p_type.builtin_type);
+ } break;
+ case GDScriptDataType::NATIVE: {
+ int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_type.native_type];
+ class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS);
+ append(GDScriptFunction::OPCODE_CAST_TO_NATIVE);
+ append(class_idx);
+ } break;
+ case GDScriptDataType::SCRIPT:
+ case GDScriptDataType::GDSCRIPT: {
+ Variant script = p_type.script_type;
+ int idx = get_constant_pos(script);
+
+ append(GDScriptFunction::OPCODE_CAST_TO_SCRIPT);
+ append(idx);
+ } break;
+ default: {
+ return;
+ }
+ }
+
+ append(p_source);
+ append(p_target);
+}
+
+void GDScriptByteCodeGenerator::write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) {
+ append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN);
+ append(p_arguments.size());
+ append(p_base);
+ append(p_function_name);
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ alloc_call(p_arguments.size());
+}
+
+void GDScriptByteCodeGenerator::write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) {
+ append(GDScriptFunction::OPCODE_CALL_SELF_BASE);
+ append(p_function_name);
+ append(p_arguments.size());
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ alloc_call(p_arguments.size());
+}
+
+void GDScriptByteCodeGenerator::write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) {
+ append(GDScriptFunction::OPCODE_CALL_ASYNC);
+ append(p_arguments.size());
+ append(p_base);
+ append(p_function_name);
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ alloc_call(p_arguments.size());
+}
+
+void GDScriptByteCodeGenerator::write_call_builtin(const Address &p_target, GDScriptFunctions::Function p_function, const Vector<Address> &p_arguments) {
+ append(GDScriptFunction::OPCODE_CALL_BUILT_IN);
+ append(p_function);
+ append(p_arguments.size());
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ alloc_call(p_arguments.size());
+}
+
+void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target, const Address &p_base, const MethodBind *p_method, const Vector<Address> &p_arguments) {
+ append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN);
+ append(p_arguments.size());
+ append(p_base);
+ append(p_method->get_name());
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ alloc_call(p_arguments.size());
+}
+
+void GDScriptByteCodeGenerator::write_call_ptrcall(const Address &p_target, const Address &p_base, const MethodBind *p_method, const Vector<Address> &p_arguments) {
+ append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN);
+ append(p_arguments.size());
+ append(p_base);
+ append(p_method->get_name());
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ alloc_call(p_arguments.size());
+}
+
+void GDScriptByteCodeGenerator::write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) {
+ append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN);
+ append(p_arguments.size());
+ append(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS);
+ append(p_function_name);
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ alloc_call(p_arguments.size());
+}
+
+void GDScriptByteCodeGenerator::write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) {
+ append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN);
+ append(p_arguments.size());
+ append(p_base);
+ append(p_function_name);
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ alloc_call(p_arguments.size());
+}
+
+void GDScriptByteCodeGenerator::write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) {
+ append(GDScriptFunction::OPCODE_CONSTRUCT);
+ append(p_type);
+ append(p_arguments.size());
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+}
+
+void GDScriptByteCodeGenerator::write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) {
+ append(GDScriptFunction::OPCODE_CONSTRUCT_ARRAY);
+ append(p_arguments.size());
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+}
+
+void GDScriptByteCodeGenerator::write_construct_dictionary(const Address &p_target, const Vector<Address> &p_arguments) {
+ append(GDScriptFunction::OPCODE_CONSTRUCT_DICTIONARY);
+ append(p_arguments.size() / 2); // This is number of key-value pairs, so only half of actual arguments.
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+}
+
+void GDScriptByteCodeGenerator::write_await(const Address &p_target, const Address &p_operand) {
+ append(GDScriptFunction::OPCODE_AWAIT);
+ append(p_operand);
+ append(GDScriptFunction::OPCODE_AWAIT_RESUME);
+ append(p_target);
+}
+
+void GDScriptByteCodeGenerator::write_if(const Address &p_condition) {
+ append(GDScriptFunction::OPCODE_JUMP_IF_NOT);
+ append(p_condition);
+ if_jmp_addrs.push_back(opcodes.size());
+ append(0); // Jump destination, will be patched.
+}
+
+void GDScriptByteCodeGenerator::write_else() {
+ append(GDScriptFunction::OPCODE_JUMP); // Jump from true if block;
+ int else_jmp_addr = opcodes.size();
+ append(0); // Jump destination, will be patched.
+
+ patch_jump(if_jmp_addrs.back()->get());
+ if_jmp_addrs.pop_back();
+ if_jmp_addrs.push_back(else_jmp_addr);
+}
+
+void GDScriptByteCodeGenerator::write_endif() {
+ patch_jump(if_jmp_addrs.back()->get());
+ if_jmp_addrs.pop_back();
+}
+
+void GDScriptByteCodeGenerator::write_for(const Address &p_variable, const Address &p_list) {
+ int counter_pos = increase_stack() | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
+ int container_pos = increase_stack() | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
+
+ current_breaks_to_patch.push_back(List<int>());
+
+ // Assign container.
+ append(GDScriptFunction::OPCODE_ASSIGN);
+ append(container_pos);
+ append(p_list);
+
+ // Begin loop.
+ append(GDScriptFunction::OPCODE_ITERATE_BEGIN);
+ append(counter_pos);
+ append(container_pos);
+ for_jmp_addrs.push_back(opcodes.size());
+ append(0); // End of loop address, will be patched.
+ append(p_variable);
+ append(GDScriptFunction::OPCODE_JUMP);
+ append(opcodes.size() + 6); // Skip over 'continue' code.
+
+ // Next iteration.
+ int continue_addr = opcodes.size();
+ continue_addrs.push_back(continue_addr);
+ append(GDScriptFunction::OPCODE_ITERATE);
+ append(counter_pos);
+ append(container_pos);
+ for_jmp_addrs.push_back(opcodes.size());
+ append(0); // Jump destination, will be patched.
+ append(p_variable);
+}
+
+void GDScriptByteCodeGenerator::write_endfor() {
+ // Jump back to loop check.
+ append(GDScriptFunction::OPCODE_JUMP);
+ append(continue_addrs.back()->get());
+ continue_addrs.pop_back();
+
+ // Patch end jumps (two of them).
+ for (int i = 0; i < 2; i++) {
+ patch_jump(for_jmp_addrs.back()->get());
+ for_jmp_addrs.pop_back();
+ }
+
+ // Patch break statements.
+ for (const List<int>::Element *E = current_breaks_to_patch.back()->get().front(); E; E = E->next()) {
+ patch_jump(E->get());
+ }
+ current_breaks_to_patch.pop_back();
+
+ current_stack_size -= 2; // Remove loop temporaries.
+}
+
+void GDScriptByteCodeGenerator::start_while_condition() {
+ current_breaks_to_patch.push_back(List<int>());
+ continue_addrs.push_back(opcodes.size());
+}
+
+void GDScriptByteCodeGenerator::write_while(const Address &p_condition) {
+ // Condition check.
+ append(GDScriptFunction::OPCODE_JUMP_IF_NOT);
+ append(p_condition);
+ while_jmp_addrs.push_back(opcodes.size());
+ append(0); // End of loop address, will be patched.
+}
+
+void GDScriptByteCodeGenerator::write_endwhile() {
+ // Jump back to loop check.
+ append(GDScriptFunction::OPCODE_JUMP);
+ append(continue_addrs.back()->get());
+ continue_addrs.pop_back();
+
+ // Patch end jump.
+ patch_jump(while_jmp_addrs.back()->get());
+ while_jmp_addrs.pop_back();
+
+ // Patch break statements.
+ for (const List<int>::Element *E = current_breaks_to_patch.back()->get().front(); E; E = E->next()) {
+ patch_jump(E->get());
+ }
+ current_breaks_to_patch.pop_back();
+}
+
+void GDScriptByteCodeGenerator::start_match() {
+ match_continues_to_patch.push_back(List<int>());
+}
+
+void GDScriptByteCodeGenerator::start_match_branch() {
+ // Patch continue statements.
+ for (const List<int>::Element *E = match_continues_to_patch.back()->get().front(); E; E = E->next()) {
+ patch_jump(E->get());
+ }
+ match_continues_to_patch.pop_back();
+ // Start a new list for next branch.
+ match_continues_to_patch.push_back(List<int>());
+}
+
+void GDScriptByteCodeGenerator::end_match() {
+ // Patch continue statements.
+ for (const List<int>::Element *E = match_continues_to_patch.back()->get().front(); E; E = E->next()) {
+ patch_jump(E->get());
+ }
+ match_continues_to_patch.pop_back();
+}
+
+void GDScriptByteCodeGenerator::write_break() {
+ append(GDScriptFunction::OPCODE_JUMP);
+ current_breaks_to_patch.back()->get().push_back(opcodes.size());
+ append(0);
+}
+
+void GDScriptByteCodeGenerator::write_continue() {
+ append(GDScriptFunction::OPCODE_JUMP);
+ append(continue_addrs.back()->get());
+}
+
+void GDScriptByteCodeGenerator::write_continue_match() {
+ append(GDScriptFunction::OPCODE_JUMP);
+ match_continues_to_patch.back()->get().push_back(opcodes.size());
+ append(0);
+}
+
+void GDScriptByteCodeGenerator::write_breakpoint() {
+ append(GDScriptFunction::OPCODE_BREAKPOINT);
+}
+
+void GDScriptByteCodeGenerator::write_newline(int p_line) {
+ append(GDScriptFunction::OPCODE_LINE);
+ append(p_line);
+ current_line = p_line;
+}
+
+void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {
+ append(GDScriptFunction::OPCODE_RETURN);
+ append(p_return_value);
+}
+
+void GDScriptByteCodeGenerator::write_assert(const Address &p_test, const Address &p_message) {
+ append(GDScriptFunction::OPCODE_ASSERT);
+ append(p_test);
+ append(p_message);
+}
+
+void GDScriptByteCodeGenerator::start_block() {
+ push_stack_identifiers();
+}
+
+void GDScriptByteCodeGenerator::end_block() {
+ pop_stack_identifiers();
+}
+
+GDScriptByteCodeGenerator::~GDScriptByteCodeGenerator() {
+ if (!ended && function != nullptr) {
+ memdelete(function);
+ }
+}
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
new file mode 100644
index 0000000000..62438b6dd2
--- /dev/null
+++ b/modules/gdscript/gdscript_byte_codegen.h
@@ -0,0 +1,277 @@
+/*************************************************************************/
+/* gdscript_byte_codegen.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GDSCRIPT_BYTE_CODEGEN
+#define GDSCRIPT_BYTE_CODEGEN
+
+#include "gdscript_codegen.h"
+
+class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
+ bool ended = false;
+ GDScriptFunction *function = nullptr;
+ bool debug_stack = false;
+
+ Vector<int> opcodes;
+ List<Map<StringName, int>> stack_id_stack;
+ Map<StringName, int> stack_identifiers;
+ Map<StringName, int> local_constants;
+
+ List<GDScriptFunction::StackDebug> stack_debug;
+ List<Map<StringName, int>> block_identifier_stack;
+ Map<StringName, int> block_identifiers;
+
+ int current_stack_size = 0;
+ int current_temporaries = 0;
+
+ HashMap<Variant, int, VariantHasher, VariantComparator> constant_map;
+ Map<StringName, int> name_map;
+#ifdef TOOLS_ENABLED
+ Vector<StringName> named_globals;
+#endif
+ int current_line = 0;
+ int stack_max = 0;
+ int call_max = 0;
+
+ List<int> if_jmp_addrs; // List since this can be nested.
+ List<int> for_jmp_addrs;
+ List<int> while_jmp_addrs;
+ List<int> continue_addrs;
+
+ // Used to patch jumps with `and` and `or` operators with short-circuit.
+ List<int> logic_op_jump_pos1;
+ List<int> logic_op_jump_pos2;
+
+ List<Address> ternary_result;
+ List<int> ternary_jump_fail_pos;
+ List<int> ternary_jump_skip_pos;
+
+ List<List<int>> current_breaks_to_patch;
+ List<List<int>> match_continues_to_patch;
+
+ void add_stack_identifier(const StringName &p_id, int p_stackpos) {
+ stack_identifiers[p_id] = p_stackpos;
+ if (debug_stack) {
+ block_identifiers[p_id] = p_stackpos;
+ GDScriptFunction::StackDebug sd;
+ sd.added = true;
+ sd.line = current_line;
+ sd.identifier = p_id;
+ sd.pos = p_stackpos;
+ stack_debug.push_back(sd);
+ }
+ }
+
+ void push_stack_identifiers() {
+ stack_id_stack.push_back(stack_identifiers);
+ if (debug_stack) {
+ block_identifier_stack.push_back(block_identifiers);
+ block_identifiers.clear();
+ }
+ }
+
+ void pop_stack_identifiers() {
+ stack_identifiers = stack_id_stack.back()->get();
+ current_stack_size = stack_identifiers.size() + current_temporaries;
+ stack_id_stack.pop_back();
+
+ if (debug_stack) {
+ for (Map<StringName, int>::Element *E = block_identifiers.front(); E; E = E->next()) {
+ GDScriptFunction::StackDebug sd;
+ sd.added = false;
+ sd.identifier = E->key();
+ sd.line = current_line;
+ sd.pos = E->get();
+ stack_debug.push_back(sd);
+ }
+ block_identifiers = block_identifier_stack.back()->get();
+ block_identifier_stack.pop_back();
+ }
+ }
+
+ int get_name_map_pos(const StringName &p_identifier) {
+ int ret;
+ if (!name_map.has(p_identifier)) {
+ ret = name_map.size();
+ name_map[p_identifier] = ret;
+ } else {
+ ret = name_map[p_identifier];
+ }
+ return ret;
+ }
+
+ int get_constant_pos(const Variant &p_constant) {
+ if (constant_map.has(p_constant))
+ return constant_map[p_constant];
+ int pos = constant_map.size();
+ constant_map[p_constant] = pos;
+ return pos;
+ }
+
+ void alloc_stack(int p_level) {
+ if (p_level >= stack_max)
+ stack_max = p_level + 1;
+ }
+
+ void alloc_call(int p_params) {
+ if (p_params >= call_max)
+ call_max = p_params;
+ }
+
+ int increase_stack() {
+ int top = current_stack_size++;
+ alloc_stack(current_stack_size);
+ return top;
+ }
+
+ int address_of(const Address &p_address) {
+ switch (p_address.mode) {
+ case Address::SELF:
+ return GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS;
+ case Address::CLASS:
+ return GDScriptFunction::ADDR_TYPE_CLASS << GDScriptFunction::ADDR_BITS;
+ case Address::MEMBER:
+ return p_address.address | (GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS);
+ case Address::CLASS_CONSTANT:
+ return p_address.address | (GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT << GDScriptFunction::ADDR_BITS);
+ case Address::LOCAL_CONSTANT:
+ case Address::CONSTANT:
+ return p_address.address | (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
+ case Address::LOCAL_VARIABLE:
+ case Address::TEMPORARY:
+ case Address::FUNCTION_PARAMETER:
+ return p_address.address | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
+ case Address::GLOBAL:
+ return p_address.address | (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS);
+ case Address::NAMED_GLOBAL:
+ return p_address.address | (GDScriptFunction::ADDR_TYPE_NAMED_GLOBAL << GDScriptFunction::ADDR_BITS);
+ case Address::NIL:
+ return GDScriptFunction::ADDR_TYPE_NIL << GDScriptFunction::ADDR_BITS;
+ }
+ return -1; // Unreachable.
+ }
+
+ void append(int code) {
+ opcodes.push_back(code);
+ }
+
+ void append(const Address &p_address) {
+ opcodes.push_back(address_of(p_address));
+ }
+
+ void append(const StringName &p_name) {
+ opcodes.push_back(get_name_map_pos(p_name));
+ }
+
+ void patch_jump(int p_address) {
+ opcodes.write[p_address] = opcodes.size();
+ }
+
+public:
+ virtual uint32_t add_parameter(const StringName &p_name, bool p_is_optional, const GDScriptDataType &p_type) override;
+ virtual uint32_t add_local(const StringName &p_name, const GDScriptDataType &p_type) override;
+ virtual uint32_t add_local_constant(const StringName &p_name, const Variant &p_constant) override;
+ virtual uint32_t add_or_get_constant(const Variant &p_constant) override;
+ virtual uint32_t add_or_get_name(const StringName &p_name) override;
+ virtual uint32_t add_temporary() override;
+ virtual void pop_temporary() override;
+
+ virtual void start_parameters() override;
+ virtual void end_parameters() override;
+
+ virtual void start_block() override;
+ virtual void end_block() override;
+
+ virtual void write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCMode p_rpc_mode, const GDScriptDataType &p_return_type) override;
+ virtual GDScriptFunction *write_end() override;
+
+#ifdef DEBUG_ENABLED
+ virtual void set_signature(const String &p_signature) override;
+#endif
+ virtual void set_initial_line(int p_line) override;
+
+ virtual void write_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) override;
+ virtual void write_type_test(const Address &p_target, const Address &p_source, const Address &p_type) override;
+ virtual void write_type_test_builtin(const Address &p_target, const Address &p_source, Variant::Type p_type) override;
+ virtual void write_and_left_operand(const Address &p_left_operand) override;
+ virtual void write_and_right_operand(const Address &p_right_operand) override;
+ virtual void write_end_and(const Address &p_target) override;
+ virtual void write_or_left_operand(const Address &p_left_operand) override;
+ virtual void write_or_right_operand(const Address &p_right_operand) override;
+ virtual void write_end_or(const Address &p_target) override;
+ virtual void write_start_ternary(const Address &p_target) override;
+ virtual void write_ternary_condition(const Address &p_condition) override;
+ virtual void write_ternary_true_expr(const Address &p_expr) override;
+ virtual void write_ternary_false_expr(const Address &p_expr) override;
+ virtual void write_end_ternary() override;
+ virtual void write_set(const Address &p_target, const Address &p_index, const Address &p_source) override;
+ virtual void write_get(const Address &p_target, const Address &p_index, const Address &p_source) override;
+ virtual void write_set_named(const Address &p_target, const StringName &p_name, const Address &p_source) override;
+ virtual void write_get_named(const Address &p_target, const StringName &p_name, const Address &p_source) override;
+ virtual void write_set_member(const Address &p_value, const StringName &p_name) override;
+ virtual void write_get_member(const Address &p_target, const StringName &p_name) override;
+ virtual void write_assign(const Address &p_target, const Address &p_source) override;
+ virtual void write_assign_true(const Address &p_target) override;
+ virtual void write_assign_false(const Address &p_target) override;
+ virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) override;
+ virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
+ virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
+ virtual void write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
+ virtual void write_call_builtin(const Address &p_target, GDScriptFunctions::Function p_function, const Vector<Address> &p_arguments) override;
+ virtual void write_call_method_bind(const Address &p_target, const Address &p_base, const MethodBind *p_method, const Vector<Address> &p_arguments) override;
+ virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, const MethodBind *p_method, const Vector<Address> &p_arguments) override;
+ virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
+ virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
+ virtual void write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) override;
+ virtual void write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) override;
+ virtual void write_construct_dictionary(const Address &p_target, const Vector<Address> &p_arguments) override;
+ virtual void write_await(const Address &p_target, const Address &p_operand) override;
+ virtual void write_if(const Address &p_condition) override;
+ virtual void write_else() override;
+ virtual void write_endif() override;
+ virtual void write_for(const Address &p_variable, const Address &p_list) override;
+ virtual void write_endfor() override;
+ virtual void start_while_condition() override;
+ virtual void write_while(const Address &p_condition) override;
+ virtual void write_endwhile() override;
+ virtual void start_match() override;
+ virtual void start_match_branch() override;
+ virtual void end_match() override;
+ virtual void write_break() override;
+ virtual void write_continue() override;
+ virtual void write_continue_match() override;
+ virtual void write_breakpoint() override;
+ virtual void write_newline(int p_line) override;
+ virtual void write_return(const Address &p_return_value) override;
+ virtual void write_assert(const Address &p_test, const Address &p_message) override;
+
+ virtual ~GDScriptByteCodeGenerator();
+};
+
+#endif // GDSCRIPT_BYTE_CODEGEN
diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index cdb14d6281..992f8f4b58 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -127,7 +127,7 @@ Ref<GDScriptParserRef> GDScriptCache::get_parser(const String &p_path, GDScriptP
singleton->dependencies[p_owner].insert(p_path);
}
if (singleton->parser_map.has(p_path)) {
- ref = singleton->parser_map[p_path];
+ ref = Ref<GDScriptParserRef>(singleton->parser_map[p_path]);
} else {
if (!FileAccess::exists(p_path)) {
r_error = ERR_FILE_NOT_FOUND;
@@ -137,8 +137,7 @@ Ref<GDScriptParserRef> GDScriptCache::get_parser(const String &p_path, GDScriptP
ref.instance();
ref->parser = parser;
ref->path = p_path;
- singleton->parser_map[p_path] = ref;
- ref->unreference();
+ singleton->parser_map[p_path] = ref.ptr();
}
r_error = ref->raise_status(p_status);
@@ -186,10 +185,7 @@ Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, const Stri
script->set_script_path(p_path);
script->load_source_code(p_path);
- singleton->shallow_gdscript_cache[p_path] = script;
- // The one in cache is not a hard reference: if the script dies somewhere else it's fine.
- // Scripts remove themselves from cache when they die.
- script->unreference();
+ singleton->shallow_gdscript_cache[p_path] = script.ptr();
return script;
}
@@ -217,7 +213,7 @@ Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_erro
return script;
}
- singleton->full_gdscript_cache[p_path] = script;
+ singleton->full_gdscript_cache[p_path] = script.ptr();
singleton->shallow_gdscript_cache.erase(p_path);
return script;
@@ -226,7 +222,7 @@ Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_erro
Error GDScriptCache::finish_compiling(const String &p_owner) {
// Mark this as compiled.
Ref<GDScript> script = get_shallow_script(p_owner);
- singleton->full_gdscript_cache[p_owner] = script;
+ singleton->full_gdscript_cache[p_owner] = script.ptr();
singleton->shallow_gdscript_cache.erase(p_owner);
Set<String> depends = singleton->dependencies[p_owner];
diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h
index 770704d6eb..865df34051 100644
--- a/modules/gdscript/gdscript_cache.h
+++ b/modules/gdscript/gdscript_cache.h
@@ -70,9 +70,9 @@ public:
class GDScriptCache {
// String key is full path.
- HashMap<String, Ref<GDScriptParserRef>> parser_map;
- HashMap<String, Ref<GDScript>> shallow_gdscript_cache;
- HashMap<String, Ref<GDScript>> full_gdscript_cache;
+ HashMap<String, GDScriptParserRef *> parser_map;
+ HashMap<String, GDScript *> shallow_gdscript_cache;
+ HashMap<String, GDScript *> full_gdscript_cache;
HashMap<String, Set<String>> dependencies;
friend class GDScript;
diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h
new file mode 100644
index 0000000000..31e1e6ba23
--- /dev/null
+++ b/modules/gdscript/gdscript_codegen.h
@@ -0,0 +1,160 @@
+/*************************************************************************/
+/* gdscript_codegen.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GDSCRIPT_CODEGEN
+#define GDSCRIPT_CODEGEN
+
+#include "core/io/multiplayer_api.h"
+#include "core/string_name.h"
+#include "core/variant.h"
+#include "gdscript_function.h"
+#include "gdscript_functions.h"
+
+class GDScriptCodeGenerator {
+public:
+ struct Address {
+ enum AddressMode {
+ SELF,
+ CLASS,
+ MEMBER,
+ CONSTANT,
+ CLASS_CONSTANT,
+ LOCAL_CONSTANT,
+ LOCAL_VARIABLE,
+ FUNCTION_PARAMETER,
+ TEMPORARY,
+ GLOBAL,
+ NAMED_GLOBAL,
+ NIL,
+ };
+ AddressMode mode = NIL;
+ uint32_t address = 0;
+ GDScriptDataType type;
+
+ Address() {}
+ Address(AddressMode p_mode, const GDScriptDataType &p_type = GDScriptDataType()) {
+ mode = p_mode;
+ type = p_type;
+ }
+ Address(AddressMode p_mode, uint32_t p_address, const GDScriptDataType &p_type = GDScriptDataType()) {
+ mode = p_mode,
+ address = p_address;
+ type = p_type;
+ }
+ };
+
+ virtual uint32_t add_parameter(const StringName &p_name, bool p_is_optional, const GDScriptDataType &p_type) = 0;
+ virtual uint32_t add_local(const StringName &p_name, const GDScriptDataType &p_type) = 0;
+ virtual uint32_t add_local_constant(const StringName &p_name, const Variant &p_constant) = 0;
+ virtual uint32_t add_or_get_constant(const Variant &p_constant) = 0;
+ virtual uint32_t add_or_get_name(const StringName &p_name) = 0;
+ virtual uint32_t add_temporary() = 0;
+ virtual void pop_temporary() = 0;
+
+ virtual void start_parameters() = 0;
+ virtual void end_parameters() = 0;
+
+ virtual void start_block() = 0;
+ virtual void end_block() = 0;
+
+ // virtual int get_max_stack_level() = 0;
+ // virtual int get_max_function_arguments() = 0;
+
+ virtual void write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, MultiplayerAPI::RPCMode p_rpc_mode, const GDScriptDataType &p_return_type) = 0;
+ virtual GDScriptFunction *write_end() = 0;
+
+#ifdef DEBUG_ENABLED
+ virtual void set_signature(const String &p_signature) = 0;
+#endif
+ virtual void set_initial_line(int p_line) = 0;
+
+ // virtual void alloc_stack(int p_level) = 0; // Is this needed?
+ // virtual void alloc_call(int p_arg_count) = 0; // This might be automatic from other functions.
+
+ virtual void write_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) = 0;
+ virtual void write_type_test(const Address &p_target, const Address &p_source, const Address &p_type) = 0;
+ virtual void write_type_test_builtin(const Address &p_target, const Address &p_source, Variant::Type p_type) = 0;
+ virtual void write_and_left_operand(const Address &p_left_operand) = 0;
+ virtual void write_and_right_operand(const Address &p_right_operand) = 0;
+ virtual void write_end_and(const Address &p_target) = 0;
+ virtual void write_or_left_operand(const Address &p_left_operand) = 0;
+ virtual void write_or_right_operand(const Address &p_right_operand) = 0;
+ virtual void write_end_or(const Address &p_target) = 0;
+ virtual void write_start_ternary(const Address &p_target) = 0;
+ virtual void write_ternary_condition(const Address &p_condition) = 0;
+ virtual void write_ternary_true_expr(const Address &p_expr) = 0;
+ virtual void write_ternary_false_expr(const Address &p_expr) = 0;
+ virtual void write_end_ternary() = 0;
+ virtual void write_set(const Address &p_target, const Address &p_index, const Address &p_source) = 0;
+ virtual void write_get(const Address &p_target, const Address &p_index, const Address &p_source) = 0;
+ virtual void write_set_named(const Address &p_target, const StringName &p_name, const Address &p_source) = 0;
+ virtual void write_get_named(const Address &p_target, const StringName &p_name, const Address &p_source) = 0;
+ virtual void write_set_member(const Address &p_value, const StringName &p_name) = 0;
+ virtual void write_get_member(const Address &p_target, const StringName &p_name) = 0;
+ virtual void write_assign(const Address &p_target, const Address &p_source) = 0;
+ virtual void write_assign_true(const Address &p_target) = 0;
+ virtual void write_assign_false(const Address &p_target) = 0;
+ virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) = 0;
+ virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
+ virtual void write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
+ virtual void write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
+ virtual void write_call_builtin(const Address &p_target, GDScriptFunctions::Function p_function, const Vector<Address> &p_arguments) = 0;
+ virtual void write_call_method_bind(const Address &p_target, const Address &p_base, const MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
+ virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, const MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
+ virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
+ virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
+ virtual void write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) = 0;
+ virtual void write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) = 0;
+ virtual void write_construct_dictionary(const Address &p_target, const Vector<Address> &p_arguments) = 0;
+ virtual void write_await(const Address &p_target, const Address &p_operand) = 0;
+ virtual void write_if(const Address &p_condition) = 0;
+ // virtual void write_elseif(const Address &p_condition) = 0; This kind of makes things more difficult for no real benefit.
+ virtual void write_else() = 0;
+ virtual void write_endif() = 0;
+ virtual void write_for(const Address &p_variable, const Address &p_list) = 0;
+ virtual void write_endfor() = 0;
+ virtual void start_while_condition() = 0; // Used to allow a jump to the expression evaluation.
+ virtual void write_while(const Address &p_condition) = 0;
+ virtual void write_endwhile() = 0;
+ virtual void start_match() = 0;
+ virtual void start_match_branch() = 0;
+ virtual void end_match() = 0;
+ virtual void write_break() = 0;
+ virtual void write_continue() = 0;
+ virtual void write_continue_match() = 0;
+ virtual void write_breakpoint() = 0;
+ virtual void write_newline(int p_line) = 0;
+ virtual void write_return(const Address &p_return_value) = 0;
+ virtual void write_assert(const Address &p_test, const Address &p_message) = 0;
+
+ virtual ~GDScriptCodeGenerator() {}
+};
+
+#endif // GDSCRIPT_CODEGEN
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index e34d87f5cc..c3d651ee79 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -31,6 +31,7 @@
#include "gdscript_compiler.h"
#include "gdscript.h"
+#include "gdscript_byte_codegen.h"
#include "gdscript_cache.h"
bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringName &p_name) {
@@ -38,7 +39,7 @@ bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringN
return false;
}
- if (codegen.stack_identifiers.has(p_name)) {
+ if (codegen.locals.has(p_name)) {
return false; //shadowed
}
@@ -75,45 +76,6 @@ void GDScriptCompiler::_set_error(const String &p_error, const GDScriptParser::N
}
}
-bool GDScriptCompiler::_create_unary_operator(CodeGen &codegen, const GDScriptParser::UnaryOpNode *on, Variant::Operator op, int p_stack_level) {
- int src_address_a = _parse_expression(codegen, on->operand, p_stack_level);
- if (src_address_a < 0) {
- return false;
- }
-
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_OPERATOR); // perform operator
- codegen.opcodes.push_back(op); //which operator
- codegen.opcodes.push_back(src_address_a); // argument 1
- codegen.opcodes.push_back(src_address_a); // argument 2 (repeated)
- //codegen.opcodes.push_back(GDScriptFunction::ADDR_TYPE_NIL); // argument 2 (unary only takes one parameter)
- return true;
-}
-
-bool GDScriptCompiler::_create_binary_operator(CodeGen &codegen, const GDScriptParser::ExpressionNode *p_left_operand, const GDScriptParser::ExpressionNode *p_right_operand, Variant::Operator op, int p_stack_level, bool p_initializer, int p_index_addr) {
- int src_address_a = _parse_expression(codegen, p_left_operand, p_stack_level, false, p_initializer, p_index_addr);
- if (src_address_a < 0) {
- return false;
- }
- if (src_address_a & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) {
- p_stack_level++; //uses stack for return, increase stack
- }
-
- int src_address_b = _parse_expression(codegen, p_right_operand, p_stack_level, false, p_initializer);
- if (src_address_b < 0) {
- return false;
- }
-
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_OPERATOR); // perform operator
- codegen.opcodes.push_back(op); //which operator
- codegen.opcodes.push_back(src_address_a); // argument 1
- codegen.opcodes.push_back(src_address_b); // argument 2 (unary only takes one parameter)
- return true;
-}
-
-bool GDScriptCompiler::_create_binary_operator(CodeGen &codegen, const GDScriptParser::BinaryOpNode *on, Variant::Operator op, int p_stack_level, bool p_initializer, int p_index_addr) {
- return _create_binary_operator(codegen, on->left_operand, on->right_operand, op, p_stack_level, p_initializer, p_index_addr);
-}
-
GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::DataType &p_datatype) const {
if (!p_datatype.is_set() || !p_datatype.is_hard_type()) {
return GDScriptDataType();
@@ -190,199 +152,64 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
return result;
}
-int GDScriptCompiler::_parse_assign_right_expression(CodeGen &codegen, const GDScriptParser::AssignmentNode *p_assignment, int p_stack_level, int p_index_addr) {
- Variant::Operator var_op = Variant::OP_MAX;
-
- switch (p_assignment->operation) {
- case GDScriptParser::AssignmentNode::OP_ADDITION:
- var_op = Variant::OP_ADD;
- break;
- case GDScriptParser::AssignmentNode::OP_SUBTRACTION:
- var_op = Variant::OP_SUBTRACT;
- break;
- case GDScriptParser::AssignmentNode::OP_MULTIPLICATION:
- var_op = Variant::OP_MULTIPLY;
- break;
- case GDScriptParser::AssignmentNode::OP_DIVISION:
- var_op = Variant::OP_DIVIDE;
- break;
- case GDScriptParser::AssignmentNode::OP_MODULO:
- var_op = Variant::OP_MODULE;
- break;
- case GDScriptParser::AssignmentNode::OP_BIT_SHIFT_LEFT:
- var_op = Variant::OP_SHIFT_LEFT;
- break;
- case GDScriptParser::AssignmentNode::OP_BIT_SHIFT_RIGHT:
- var_op = Variant::OP_SHIFT_RIGHT;
- break;
- case GDScriptParser::AssignmentNode::OP_BIT_AND:
- var_op = Variant::OP_BIT_AND;
- break;
- case GDScriptParser::AssignmentNode::OP_BIT_OR:
- var_op = Variant::OP_BIT_OR;
- break;
- case GDScriptParser::AssignmentNode::OP_BIT_XOR:
- var_op = Variant::OP_BIT_XOR;
- break;
- case GDScriptParser::AssignmentNode::OP_NONE: {
- //none
- } break;
- default: {
- ERR_FAIL_V(-1);
- }
- }
-
- // bool initializer = p_expression->op == GDScriptParser::OperatorNode::OP_INIT_ASSIGN;
-
- if (var_op == Variant::OP_MAX) {
- return _parse_expression(codegen, p_assignment->assigned_value, p_stack_level, false, false);
- }
-
- if (!_create_binary_operator(codegen, p_assignment->assignee, p_assignment->assigned_value, var_op, p_stack_level, false, p_index_addr)) {
- return -1;
- }
-
- int dst_addr = (p_stack_level) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
- codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode
- codegen.alloc_stack(p_stack_level);
- return dst_addr;
-}
-
-bool GDScriptCompiler::_generate_typed_assign(CodeGen &codegen, int p_src_address, int p_dst_address, const GDScriptDataType &p_datatype, const GDScriptParser::DataType &p_value_type) {
- if (p_datatype.has_type && p_value_type.is_variant()) {
- // Typed assignment
- switch (p_datatype.kind) {
- case GDScriptDataType::BUILTIN: {
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN); // perform operator
- codegen.opcodes.push_back(p_datatype.builtin_type); // variable type
- codegen.opcodes.push_back(p_dst_address); // argument 1
- codegen.opcodes.push_back(p_src_address); // argument 2
- } break;
- case GDScriptDataType::NATIVE: {
- int class_idx;
- if (GDScriptLanguage::get_singleton()->get_global_map().has(p_datatype.native_type)) {
- class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_datatype.native_type];
- class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); //argument (stack root)
- } else {
- // _set_error("Invalid native class type '" + String(p_datatype.native_type) + "'.", on->arguments[0]);
- return false;
- }
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_NATIVE); // perform operator
- codegen.opcodes.push_back(class_idx); // variable type
- codegen.opcodes.push_back(p_dst_address); // argument 1
- codegen.opcodes.push_back(p_src_address); // argument 2
- } break;
- case GDScriptDataType::SCRIPT:
- case GDScriptDataType::GDSCRIPT: {
- Variant script = p_datatype.script_type;
- int idx = codegen.get_constant_pos(script); //make it a local constant (faster access)
-
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT); // perform operator
- codegen.opcodes.push_back(idx); // variable type
- codegen.opcodes.push_back(p_dst_address); // argument 1
- codegen.opcodes.push_back(p_src_address); // argument 2
- } break;
- default: {
- ERR_PRINT("Compiler bug: unresolved assign.");
-
- // Shouldn't get here, but fail-safe to a regular assignment
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN); // perform operator
- codegen.opcodes.push_back(p_dst_address); // argument 1
- codegen.opcodes.push_back(p_src_address); // argument 2 (unary only takes one parameter)
- }
- }
- } else {
- if (p_datatype.kind == GDScriptDataType::BUILTIN && p_value_type.kind == GDScriptParser::DataType::BUILTIN && p_datatype.builtin_type != p_value_type.builtin_type) {
- // Need conversion.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN); // perform operator
- codegen.opcodes.push_back(p_datatype.builtin_type); // variable type
- codegen.opcodes.push_back(p_dst_address); // argument 1
- codegen.opcodes.push_back(p_src_address); // argument 2
- } else {
- // Either untyped assignment or already type-checked by the parser
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN); // perform operator
- codegen.opcodes.push_back(p_dst_address); // argument 1
- codegen.opcodes.push_back(p_src_address); // argument 2 (unary only takes one parameter)
- }
- }
- return true;
-}
-
-int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::ExpressionNode *p_expression, int p_stack_level, bool p_root, bool p_initializer, int p_index_addr) {
+GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::ExpressionNode *p_expression, bool p_root, bool p_initializer, const GDScriptCodeGenerator::Address &p_index_addr) {
if (p_expression->is_constant) {
- return codegen.get_constant_pos(p_expression->reduced_value);
+ return codegen.add_constant(p_expression->reduced_value);
}
+ GDScriptCodeGenerator *gen = codegen.generator;
+
switch (p_expression->type) {
- //should parse variable declaration and adjust stack accordingly...
case GDScriptParser::Node::IDENTIFIER: {
- //return identifier
- //wait, identifier could be a local variable or something else... careful here, must reference properly
- //as stack may be more interesting to work with
-
- //This could be made much simpler by just indexing "self", but done this way (with custom self-addressing modes) increases performance a lot.
-
+ // Look for identifiers in current scope.
const GDScriptParser::IdentifierNode *in = static_cast<const GDScriptParser::IdentifierNode *>(p_expression);
StringName identifier = in->name;
- // TRY STACK!
- if (!p_initializer && codegen.stack_identifiers.has(identifier)) {
- int pos = codegen.stack_identifiers[identifier];
- return pos | (GDScriptFunction::ADDR_TYPE_STACK_VARIABLE << GDScriptFunction::ADDR_BITS);
+ // Try function parameters.
+ if (codegen.parameters.has(identifier)) {
+ return codegen.parameters[identifier];
}
- // TRY LOCAL CONSTANTS!
- if (codegen.local_named_constants.has(identifier)) {
- return codegen.local_named_constants[identifier] | (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
+ // Try local variables and constants.
+ if (!p_initializer && codegen.locals.has(identifier)) {
+ return codegen.locals[identifier];
}
- // TRY CLASS MEMBER
+ // Try class members.
if (_is_class_member_property(codegen, identifier)) {
- //get property
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_GET_MEMBER); // perform operator
- codegen.opcodes.push_back(codegen.get_name_map_pos(identifier)); // argument 2 (unary only takes one parameter)
- int dst_addr = (p_stack_level) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
- codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode
- codegen.alloc_stack(p_stack_level);
- return dst_addr;
+ // Get property.
+ GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Could get the type of the class member here.
+ gen->write_get_member(temp, identifier);
+ return temp;
}
- //TRY MEMBERS!
+ // Try members.
if (!codegen.function_node || !codegen.function_node->is_static) {
- // TRY MEMBER VARIABLES!
- //static function
+ // Try member variables.
if (codegen.script->member_indices.has(identifier)) {
if (codegen.script->member_indices[identifier].getter != StringName() && codegen.script->member_indices[identifier].getter != codegen.function_name) {
// Perform getter.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_CALL_RETURN);
- codegen.opcodes.push_back(0); // Argument count.
- codegen.opcodes.push_back(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS); // Base (self).
- codegen.opcodes.push_back(codegen.get_name_map_pos(codegen.script->member_indices[identifier].getter)); // Method name.
- // Destination.
- int dst_addr = (p_stack_level) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
- codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode
- codegen.alloc_stack(p_stack_level);
- return dst_addr;
+ GDScriptCodeGenerator::Address temp = codegen.add_temporary();
+ Vector<GDScriptCodeGenerator::Address> args; // No argument needed.
+ gen->write_call_self(temp, codegen.script->member_indices[identifier].getter, args);
+ return temp;
} else {
- // No getter or inside getter: direct member access.
+ // No getter or inside getter: direct member access.,
int idx = codegen.script->member_indices[identifier].index;
- return idx | (GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS); //argument (stack root)
+ return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::MEMBER, idx, codegen.script->get_member_type(identifier));
}
}
}
- //TRY CLASS CONSTANTS
-
+ // Try class constants.
GDScript *owner = codegen.script;
while (owner) {
GDScript *scr = owner;
GDScriptNativeClass *nc = nullptr;
while (scr) {
if (scr->constants.has(identifier)) {
- //int idx=scr->constants[identifier];
- int idx = codegen.get_name_map_pos(identifier);
- return idx | (GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT << GDScriptFunction::ADDR_BITS); //argument (stack root)
+ return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CLASS_CONSTANT, gen->add_or_get_name(identifier)); // TODO: Get type here.
}
if (scr->native.is_valid()) {
nc = scr->native.ptr();
@@ -390,52 +217,37 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
scr = scr->_base;
}
- // CLASS C++ Integer Constant
-
+ // Class C++ integer constant.
if (nc) {
bool success = false;
int constant = ClassDB::get_integer_constant(nc->get_name(), identifier, &success);
if (success) {
- Variant key = constant;
- int idx;
-
- if (!codegen.constant_map.has(key)) {
- idx = codegen.constant_map.size();
- codegen.constant_map[key] = idx;
-
- } else {
- idx = codegen.constant_map[key];
- }
-
- return idx | (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS); //make it a local constant (faster access)
+ return codegen.add_constant(constant);
}
}
owner = owner->_owner;
}
- // TRY SIGNALS AND METHODS (can be made callables)
+ // Try signals and methods (can be made callables);
if (codegen.class_node->members_indices.has(identifier)) {
const GDScriptParser::ClassNode::Member &member = codegen.class_node->members[codegen.class_node->members_indices[identifier]];
if (member.type == GDScriptParser::ClassNode::Member::FUNCTION || member.type == GDScriptParser::ClassNode::Member::SIGNAL) {
// Get like it was a property.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_GET_NAMED); // perform operator
- codegen.opcodes.push_back(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS); // Self.
- codegen.opcodes.push_back(codegen.get_name_map_pos(identifier)); // argument 2 (unary only takes one parameter)
- int dst_addr = (p_stack_level) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
- codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode
- codegen.alloc_stack(p_stack_level);
- return dst_addr;
+ GDScriptCodeGenerator::Address temp = codegen.add_temporary(); // TODO: Get type here.
+ GDScriptCodeGenerator::Address self(GDScriptCodeGenerator::Address::SELF);
+
+ gen->write_get_named(temp, identifier, self);
+ return temp;
}
}
if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) {
int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
- return idx | (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); //argument (stack root)
+ return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::GLOBAL, idx); // TODO: Get type.
}
- /* TRY GLOBAL CLASSES */
-
+ // Try global classes.
if (ScriptServer::is_global_class(identifier)) {
const GDScriptParser::ClassNode *class_node = codegen.class_node;
while (class_node->outer) {
@@ -450,356 +262,209 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
res = ResourceLoader::load(ScriptServer::get_global_class_path(identifier));
if (res.is_null()) {
_set_error("Can't load global class " + String(identifier) + ", cyclic reference?", p_expression);
- return -1;
+ r_error = ERR_COMPILATION_FAILED;
+ return GDScriptCodeGenerator::Address();
}
}
- Variant key = res;
- int idx;
-
- if (!codegen.constant_map.has(key)) {
- idx = codegen.constant_map.size();
- codegen.constant_map[key] = idx;
-
- } else {
- idx = codegen.constant_map[key];
- }
-
- return idx | (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS); //make it a local constant (faster access)
+ return codegen.add_constant(res);
}
#ifdef TOOLS_ENABLED
if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(identifier)) {
- int idx = codegen.named_globals.find(identifier);
- if (idx == -1) {
- idx = codegen.named_globals.size();
- codegen.named_globals.push_back(identifier);
- }
- return idx | (GDScriptFunction::ADDR_TYPE_NAMED_GLOBAL << GDScriptFunction::ADDR_BITS);
+ return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::NAMED_GLOBAL, gen->add_or_get_name(identifier)); // TODO: Get type.
}
#endif
- //not found, error
-
+ // Not found, error.
_set_error("Identifier not found: " + String(identifier), p_expression);
-
- return -1;
-
+ r_error = ERR_COMPILATION_FAILED;
+ return GDScriptCodeGenerator::Address();
} break;
case GDScriptParser::Node::LITERAL: {
- //return constant
+ // Return constant.
const GDScriptParser::LiteralNode *cn = static_cast<const GDScriptParser::LiteralNode *>(p_expression);
- int idx;
-
- if (!codegen.constant_map.has(cn->value)) {
- idx = codegen.constant_map.size();
- codegen.constant_map[cn->value] = idx;
-
- } else {
- idx = codegen.constant_map[cn->value];
- }
-
- return idx | (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS); //argument (stack root)
-
+ return codegen.add_constant(cn->value);
} break;
case GDScriptParser::Node::SELF: {
//return constant
if (codegen.function_node && codegen.function_node->is_static) {
_set_error("'self' not present in static function!", p_expression);
- return -1;
+ r_error = ERR_COMPILATION_FAILED;
+ return GDScriptCodeGenerator::Address();
}
- return (GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS);
+ return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF);
} break;
case GDScriptParser::Node::ARRAY: {
const GDScriptParser::ArrayNode *an = static_cast<const GDScriptParser::ArrayNode *>(p_expression);
- Vector<int> values;
+ Vector<GDScriptCodeGenerator::Address> values;
- int slevel = p_stack_level;
+ // Create the result temporary first since it's the last to be killed.
+ GDScriptDataType array_type;
+ array_type.has_type = true;
+ array_type.kind = GDScriptDataType::BUILTIN;
+ array_type.builtin_type = Variant::ARRAY;
+ GDScriptCodeGenerator::Address result = codegen.add_temporary(array_type);
for (int i = 0; i < an->elements.size(); i++) {
- int ret = _parse_expression(codegen, an->elements[i], slevel);
- if (ret < 0) {
- return ret;
- }
- if ((ret >> GDScriptFunction::ADDR_BITS & GDScriptFunction::ADDR_TYPE_STACK) == GDScriptFunction::ADDR_TYPE_STACK) {
- slevel++;
- codegen.alloc_stack(slevel);
+ GDScriptCodeGenerator::Address val = _parse_expression(codegen, r_error, an->elements[i]);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
}
-
- values.push_back(ret);
+ values.push_back(val);
}
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_CONSTRUCT_ARRAY);
- codegen.opcodes.push_back(values.size());
+ gen->write_construct_array(result, values);
+
for (int i = 0; i < values.size(); i++) {
- codegen.opcodes.push_back(values[i]);
+ if (values[i].mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
}
- int dst_addr = (p_stack_level) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
- codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode
- codegen.alloc_stack(p_stack_level);
- return dst_addr;
-
+ return result;
} break;
case GDScriptParser::Node::DICTIONARY: {
const GDScriptParser::DictionaryNode *dn = static_cast<const GDScriptParser::DictionaryNode *>(p_expression);
- Vector<int> elements;
+ Vector<GDScriptCodeGenerator::Address> elements;
- int slevel = p_stack_level;
+ // Create the result temporary first since it's the last to be killed.
+ GDScriptDataType dict_type;
+ dict_type.has_type = true;
+ dict_type.kind = GDScriptDataType::BUILTIN;
+ dict_type.builtin_type = Variant::DICTIONARY;
+ GDScriptCodeGenerator::Address result = codegen.add_temporary(dict_type);
for (int i = 0; i < dn->elements.size(); i++) {
// Key.
- int ret = -1;
+ GDScriptCodeGenerator::Address element;
switch (dn->style) {
case GDScriptParser::DictionaryNode::PYTHON_DICT:
// Python-style: key is any expression.
- ret = _parse_expression(codegen, dn->elements[i].key, slevel);
- if (ret < 0) {
- return ret;
- }
- if ((ret >> GDScriptFunction::ADDR_BITS & GDScriptFunction::ADDR_TYPE_STACK) == GDScriptFunction::ADDR_TYPE_STACK) {
- slevel++;
- codegen.alloc_stack(slevel);
+ element = _parse_expression(codegen, r_error, dn->elements[i].key);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
}
break;
case GDScriptParser::DictionaryNode::LUA_TABLE:
// Lua-style: key is an identifier interpreted as string.
String key = static_cast<const GDScriptParser::IdentifierNode *>(dn->elements[i].key)->name;
- ret = codegen.get_constant_pos(key);
+ element = codegen.add_constant(key);
break;
}
- elements.push_back(ret);
+ elements.push_back(element);
- ret = _parse_expression(codegen, dn->elements[i].value, slevel);
- if (ret < 0) {
- return ret;
- }
- if ((ret >> GDScriptFunction::ADDR_BITS & GDScriptFunction::ADDR_TYPE_STACK) == GDScriptFunction::ADDR_TYPE_STACK) {
- slevel++;
- codegen.alloc_stack(slevel);
+ element = _parse_expression(codegen, r_error, dn->elements[i].value);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
}
- elements.push_back(ret);
+ elements.push_back(element);
}
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_CONSTRUCT_DICTIONARY);
- codegen.opcodes.push_back(dn->elements.size());
+ gen->write_construct_dictionary(result, elements);
+
for (int i = 0; i < elements.size(); i++) {
- codegen.opcodes.push_back(elements[i]);
+ if (elements[i].mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
}
- int dst_addr = (p_stack_level) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
- codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode
- codegen.alloc_stack(p_stack_level);
- return dst_addr;
-
+ return result;
} break;
case GDScriptParser::Node::CAST: {
const GDScriptParser::CastNode *cn = static_cast<const GDScriptParser::CastNode *>(p_expression);
+ GDScriptDataType cast_type = _gdtype_from_datatype(cn->cast_type->get_datatype());
- int slevel = p_stack_level;
- int src_addr = _parse_expression(codegen, cn->operand, slevel);
- if (src_addr < 0) {
- return src_addr;
- }
- if (src_addr & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) {
- slevel++;
- codegen.alloc_stack(slevel);
- }
+ // Create temporary for result first since it will be deleted last.
+ GDScriptCodeGenerator::Address result = codegen.add_temporary(cast_type);
- GDScriptDataType cast_type = _gdtype_from_datatype(cn->cast_type->get_datatype());
+ GDScriptCodeGenerator::Address source = _parse_expression(codegen, r_error, cn->operand);
- switch (cast_type.kind) {
- case GDScriptDataType::BUILTIN: {
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_BUILTIN);
- codegen.opcodes.push_back(cast_type.builtin_type);
- } break;
- case GDScriptDataType::NATIVE: {
- int class_idx;
- if (GDScriptLanguage::get_singleton()->get_global_map().has(cast_type.native_type)) {
- class_idx = GDScriptLanguage::get_singleton()->get_global_map()[cast_type.native_type];
- class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); //argument (stack root)
- } else {
- _set_error("Invalid native class type '" + String(cast_type.native_type) + "'.", cn);
- return -1;
- }
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_NATIVE); // perform operator
- codegen.opcodes.push_back(class_idx); // variable type
- } break;
- case GDScriptDataType::SCRIPT:
- case GDScriptDataType::GDSCRIPT: {
- Variant script = cast_type.script_type;
- int idx = codegen.get_constant_pos(script); //make it a local constant (faster access)
+ gen->write_cast(result, source, cast_type);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_SCRIPT); // perform operator
- codegen.opcodes.push_back(idx); // variable type
- } break;
- default: {
- _set_error("Parser bug: unresolved data type.", cn);
- return -1;
- }
+ if (source.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
}
- codegen.opcodes.push_back(src_addr); // source address
- int dst_addr = (p_stack_level) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
- codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode
- codegen.alloc_stack(p_stack_level);
- return dst_addr;
-
+ return source;
} break;
- //hell breaks loose
-
-#define OPERATOR_RETURN \
- int dst_addr = (p_stack_level) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); \
- codegen.opcodes.push_back(dst_addr); \
- codegen.alloc_stack(p_stack_level); \
- return dst_addr
-
case GDScriptParser::Node::CALL: {
const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(p_expression);
- if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name) != Variant::VARIANT_MAX) {
- //construct a basic type
+ GDScriptDataType type = _gdtype_from_datatype(call->get_datatype());
+ GDScriptCodeGenerator::Address result = codegen.add_temporary(type);
- Variant::Type vtype = GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name);
-
- Vector<int> arguments;
- int slevel = p_stack_level;
- for (int i = 0; i < call->arguments.size(); i++) {
- int ret = _parse_expression(codegen, call->arguments[i], slevel);
- if (ret < 0) {
- return ret;
- }
- if ((ret >> GDScriptFunction::ADDR_BITS & GDScriptFunction::ADDR_TYPE_STACK) == GDScriptFunction::ADDR_TYPE_STACK) {
- slevel++;
- codegen.alloc_stack(slevel);
- }
- arguments.push_back(ret);
+ Vector<GDScriptCodeGenerator::Address> arguments;
+ for (int i = 0; i < call->arguments.size(); i++) {
+ GDScriptCodeGenerator::Address arg = _parse_expression(codegen, r_error, call->arguments[i]);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
}
+ arguments.push_back(arg);
+ }
- //push call bytecode
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_CONSTRUCT); // basic type constructor
- codegen.opcodes.push_back(vtype); //instance
- codegen.opcodes.push_back(arguments.size()); //argument count
- codegen.alloc_call(arguments.size());
- for (int i = 0; i < arguments.size(); i++) {
- codegen.opcodes.push_back(arguments[i]); //arguments
- }
+ if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name) != Variant::VARIANT_MAX) {
+ // Construct a built-in type.
+ Variant::Type vtype = GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name);
+ gen->write_construct(result, vtype, arguments);
} else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_function(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name) != GDScriptFunctions::FUNC_MAX) {
- //built in function
-
- Vector<int> arguments;
- int slevel = p_stack_level;
- for (int i = 0; i < call->arguments.size(); i++) {
- int ret = _parse_expression(codegen, call->arguments[i], slevel);
- if (ret < 0) {
- return ret;
- }
-
- if ((ret >> GDScriptFunction::ADDR_BITS & GDScriptFunction::ADDR_TYPE_STACK) == GDScriptFunction::ADDR_TYPE_STACK) {
- slevel++;
- codegen.alloc_stack(slevel);
- }
-
- arguments.push_back(ret);
- }
-
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_CALL_BUILT_IN);
- codegen.opcodes.push_back(GDScriptParser::get_builtin_function(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name));
- codegen.opcodes.push_back(arguments.size());
- codegen.alloc_call(arguments.size());
- for (int i = 0; i < arguments.size(); i++) {
- codegen.opcodes.push_back(arguments[i]);
- }
-
+ // Built-in function.
+ GDScriptFunctions::Function func = GDScriptParser::get_builtin_function(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name);
+ gen->write_call_builtin(result, func, arguments);
} else {
- //regular function
-
+ // Regular function.
const GDScriptParser::ExpressionNode *callee = call->callee;
- Vector<int> arguments;
- int slevel = p_stack_level;
-
- // TODO: Use callables when possible if needed.
- int ret = -1;
- int super_address = -1;
if (call->is_super) {
// Super call.
- if (call->callee == nullptr) {
- // Implicit super function call.
- super_address = codegen.get_name_map_pos(codegen.function_node->identifier->name);
- } else {
- super_address = codegen.get_name_map_pos(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name);
- }
+ gen->write_super_call(result, call->function_name, arguments);
} else {
if (callee->type == GDScriptParser::Node::IDENTIFIER) {
// Self function call.
if ((codegen.function_node && codegen.function_node->is_static) || call->function_name == "new") {
- ret = (GDScriptFunction::ADDR_TYPE_CLASS << GDScriptFunction::ADDR_BITS);
+ GDScriptCodeGenerator::Address self;
+ self.mode = GDScriptCodeGenerator::Address::CLASS;
+ gen->write_call(result, self, call->function_name, arguments);
} else {
- ret = (GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS);
+ gen->write_call_self(result, call->function_name, arguments);
}
- arguments.push_back(ret);
- ret = codegen.get_name_map_pos(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name);
- arguments.push_back(ret);
} else if (callee->type == GDScriptParser::Node::SUBSCRIPT) {
const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(call->callee);
if (subscript->is_attribute) {
- ret = _parse_expression(codegen, subscript->base, slevel);
- if (ret < 0) {
- return ret;
+ GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
}
- if ((ret >> GDScriptFunction::ADDR_BITS & GDScriptFunction::ADDR_TYPE_STACK) == GDScriptFunction::ADDR_TYPE_STACK) {
- slevel++;
- codegen.alloc_stack(slevel);
+ if (within_await) {
+ gen->write_call_async(result, base, call->function_name, arguments);
+ } else {
+ gen->write_call(result, base, call->function_name, arguments);
+ }
+ if (base.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
}
- arguments.push_back(ret);
- arguments.push_back(codegen.get_name_map_pos(subscript->attribute->name));
} else {
_set_error("Cannot call something that isn't a function.", call->callee);
- return -1;
+ r_error = ERR_COMPILATION_FAILED;
+ return GDScriptCodeGenerator::Address();
}
} else {
- _set_error("Cannot call something that isn't a function.", call->callee);
- return -1;
- }
- }
-
- for (int i = 0; i < call->arguments.size(); i++) {
- ret = _parse_expression(codegen, call->arguments[i], slevel);
- if (ret < 0) {
- return ret;
+ r_error = ERR_COMPILATION_FAILED;
+ return GDScriptCodeGenerator::Address();
}
- if ((ret >> GDScriptFunction::ADDR_BITS & GDScriptFunction::ADDR_TYPE_STACK) == GDScriptFunction::ADDR_TYPE_STACK) {
- slevel++;
- codegen.alloc_stack(slevel);
- }
- arguments.push_back(ret);
- }
-
- int opcode = GDScriptFunction::OPCODE_CALL_RETURN;
- if (call->is_super) {
- opcode = GDScriptFunction::OPCODE_CALL_SELF_BASE;
- } else if (within_await) {
- opcode = GDScriptFunction::OPCODE_CALL_ASYNC;
- } else if (p_root) {
- opcode = GDScriptFunction::OPCODE_CALL;
}
+ }
- codegen.opcodes.push_back(opcode); // perform operator
- if (call->is_super) {
- codegen.opcodes.push_back(super_address);
- }
- codegen.opcodes.push_back(call->arguments.size());
- codegen.alloc_call(call->arguments.size());
- for (int i = 0; i < arguments.size(); i++) {
- codegen.opcodes.push_back(arguments[i]);
+ for (int i = 0; i < arguments.size(); i++) {
+ if (arguments[i].mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
}
}
- OPERATOR_RETURN;
+ return result;
} break;
case GDScriptParser::Node::GET_NODE: {
const GDScriptParser::GetNodeNode *get_node = static_cast<const GDScriptParser::GetNodeNode *>(p_expression);
@@ -816,59 +481,55 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
}
}
- int arg_address = codegen.get_constant_pos(NodePath(node_name));
+ Vector<GDScriptCodeGenerator::Address> args;
+ args.push_back(codegen.add_constant(NodePath(node_name)));
+
+ GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(get_node->get_datatype()));
+
+ MethodBind *get_node_method = ClassDB::get_method("Node", "get_node");
+ gen->write_call_method_bind(result, GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), get_node_method, args);
- codegen.opcodes.push_back(p_root ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN);
- codegen.opcodes.push_back(1); // number of arguments.
- codegen.alloc_call(1);
- codegen.opcodes.push_back(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS); // self.
- codegen.opcodes.push_back(codegen.get_name_map_pos("get_node")); // function.
- codegen.opcodes.push_back(arg_address); // argument (NodePath).
- OPERATOR_RETURN;
+ return result;
} break;
case GDScriptParser::Node::PRELOAD: {
const GDScriptParser::PreloadNode *preload = static_cast<const GDScriptParser::PreloadNode *>(p_expression);
// Add resource as constant.
- return codegen.get_constant_pos(preload->resource);
+ return codegen.add_constant(preload->resource);
} break;
case GDScriptParser::Node::AWAIT: {
const GDScriptParser::AwaitNode *await = static_cast<const GDScriptParser::AwaitNode *>(p_expression);
- int slevel = p_stack_level;
+ GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(p_expression->get_datatype()));
within_await = true;
- int argument = _parse_expression(codegen, await->to_await, slevel);
+ GDScriptCodeGenerator::Address argument = _parse_expression(codegen, r_error, await->to_await);
within_await = false;
- if (argument < 0) {
- return argument;
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
}
- if ((argument >> GDScriptFunction::ADDR_BITS & GDScriptFunction::ADDR_TYPE_STACK) == GDScriptFunction::ADDR_TYPE_STACK) {
- slevel++;
- codegen.alloc_stack(slevel);
+
+ gen->write_await(result, argument);
+
+ if (argument.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
}
- //push call bytecode
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_AWAIT);
- codegen.opcodes.push_back(argument);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_AWAIT_RESUME);
- //next will be where to place the result :)
- OPERATOR_RETURN;
+ return result;
} break;
-
- //indexing operator
+ // Indexing operator.
case GDScriptParser::Node::SUBSCRIPT: {
- int slevel = p_stack_level;
-
const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(p_expression);
+ GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(subscript->get_datatype()));
- int from = _parse_expression(codegen, subscript->base, slevel);
- if (from < 0) {
- return from;
+ GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
}
bool named = subscript->is_attribute;
- int index;
- if (p_index_addr != 0) {
+ StringName name;
+ GDScriptCodeGenerator::Address index;
+ if (p_index_addr.mode != GDScriptCodeGenerator::Address::NIL) {
index = p_index_addr;
} else if (subscript->is_attribute) {
if (subscript->base->type == GDScriptParser::Node::SELF && codegen.script) {
@@ -879,306 +540,179 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
if (MI && MI->get().getter == codegen.function_name) {
String n = identifier->name;
_set_error("Must use '" + n + "' instead of 'self." + n + "' in getter.", identifier);
- return -1;
+ r_error = ERR_COMPILATION_FAILED;
+ return GDScriptCodeGenerator::Address();
}
#endif
if (MI && MI->get().getter == "") {
- // Faster than indexing self (as if no self. had been used)
- return (MI->get().index) | (GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS);
+ // Remove result temp as we don't need it.
+ gen->pop_temporary();
+ // Faster than indexing self (as if no self. had been used).
+ return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::MEMBER, MI->get().index, _gdtype_from_datatype(subscript->get_datatype()));
}
}
- index = codegen.get_name_map_pos(subscript->attribute->name);
-
+ name = subscript->attribute->name;
+ named = true;
} else {
if (subscript->index->type == GDScriptParser::Node::LITERAL && static_cast<const GDScriptParser::LiteralNode *>(subscript->index)->value.get_type() == Variant::STRING) {
- //also, somehow, named (speed up anyway)
- StringName name = static_cast<const GDScriptParser::LiteralNode *>(subscript->index)->value;
- index = codegen.get_name_map_pos(name);
+ // Also, somehow, named (speed up anyway).
+ name = static_cast<const GDScriptParser::LiteralNode *>(subscript->index)->value;
named = true;
-
} else {
- //regular indexing
- if (from & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) {
- slevel++;
- codegen.alloc_stack(slevel);
- }
-
- index = _parse_expression(codegen, subscript->index, slevel);
- if (index < 0) {
- return index;
+ // Regular indexing.
+ index = _parse_expression(codegen, r_error, subscript->index);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
}
}
}
- codegen.opcodes.push_back(named ? GDScriptFunction::OPCODE_GET_NAMED : GDScriptFunction::OPCODE_GET); // perform operator
- codegen.opcodes.push_back(from); // argument 1
- codegen.opcodes.push_back(index); // argument 2 (unary only takes one parameter)
- OPERATOR_RETURN;
+ if (named) {
+ gen->write_get_named(result, name, base);
+ } else {
+ gen->write_get(result, index, base);
+ }
+
+ if (index.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
+ if (base.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
+
+ return result;
} break;
case GDScriptParser::Node::UNARY_OPERATOR: {
- //unary operators
const GDScriptParser::UnaryOpNode *unary = static_cast<const GDScriptParser::UnaryOpNode *>(p_expression);
- switch (unary->operation) {
- case GDScriptParser::UnaryOpNode::OP_NEGATIVE: {
- if (!_create_unary_operator(codegen, unary, Variant::OP_NEGATE, p_stack_level)) {
- return -1;
- }
- } break;
- case GDScriptParser::UnaryOpNode::OP_POSITIVE: {
- if (!_create_unary_operator(codegen, unary, Variant::OP_POSITIVE, p_stack_level)) {
- return -1;
- }
- } break;
- case GDScriptParser::UnaryOpNode::OP_LOGIC_NOT: {
- if (!_create_unary_operator(codegen, unary, Variant::OP_NOT, p_stack_level)) {
- return -1;
- }
- } break;
- case GDScriptParser::UnaryOpNode::OP_COMPLEMENT: {
- if (!_create_unary_operator(codegen, unary, Variant::OP_BIT_NEGATE, p_stack_level)) {
- return -1;
- }
- } break;
+
+ GDScriptCodeGenerator::Address result = codegen.add_temporary();
+
+ GDScriptCodeGenerator::Address operand = _parse_expression(codegen, r_error, unary->operand);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
+ }
+
+ gen->write_operator(result, unary->variant_op, operand, GDScriptCodeGenerator::Address());
+
+ if (operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
}
- OPERATOR_RETURN;
+
+ return result;
}
case GDScriptParser::Node::BINARY_OPERATOR: {
- //binary operators (in precedence order)
const GDScriptParser::BinaryOpNode *binary = static_cast<const GDScriptParser::BinaryOpNode *>(p_expression);
+ GDScriptCodeGenerator::Address result = codegen.add_temporary();
+
switch (binary->operation) {
case GDScriptParser::BinaryOpNode::OP_LOGIC_AND: {
- // AND operator with early out on failure
+ // AND operator with early out on failure.
+ GDScriptCodeGenerator::Address left_operand = _parse_expression(codegen, r_error, binary->left_operand);
+ gen->write_and_left_operand(left_operand);
+ GDScriptCodeGenerator::Address right_operand = _parse_expression(codegen, r_error, binary->right_operand);
+ gen->write_and_right_operand(right_operand);
- int res = _parse_expression(codegen, binary->left_operand, p_stack_level);
- if (res < 0) {
- return res;
+ gen->write_end_and(result);
+
+ if (right_operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
}
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF_NOT);
- codegen.opcodes.push_back(res);
- int jump_fail_pos = codegen.opcodes.size();
- codegen.opcodes.push_back(0);
-
- res = _parse_expression(codegen, binary->right_operand, p_stack_level);
- if (res < 0) {
- return res;
+ if (left_operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
}
-
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF_NOT);
- codegen.opcodes.push_back(res);
- int jump_fail_pos2 = codegen.opcodes.size();
- codegen.opcodes.push_back(0);
-
- codegen.alloc_stack(p_stack_level); //it will be used..
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TRUE);
- codegen.opcodes.push_back(p_stack_level | GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP);
- codegen.opcodes.push_back(codegen.opcodes.size() + 3);
- codegen.opcodes.write[jump_fail_pos] = codegen.opcodes.size();
- codegen.opcodes.write[jump_fail_pos2] = codegen.opcodes.size();
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_FALSE);
- codegen.opcodes.push_back(p_stack_level | GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
- return p_stack_level | GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS;
-
} break;
case GDScriptParser::BinaryOpNode::OP_LOGIC_OR: {
- // OR operator with early out on success
+ // OR operator with early out on success.
+ GDScriptCodeGenerator::Address left_operand = _parse_expression(codegen, r_error, binary->left_operand);
+ gen->write_or_left_operand(left_operand);
+ GDScriptCodeGenerator::Address right_operand = _parse_expression(codegen, r_error, binary->right_operand);
+ gen->write_or_right_operand(right_operand);
- int res = _parse_expression(codegen, binary->left_operand, p_stack_level);
- if (res < 0) {
- return res;
+ gen->write_end_or(result);
+
+ if (right_operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
}
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF);
- codegen.opcodes.push_back(res);
- int jump_success_pos = codegen.opcodes.size();
- codegen.opcodes.push_back(0);
-
- res = _parse_expression(codegen, binary->right_operand, p_stack_level);
- if (res < 0) {
- return res;
+ if (left_operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
}
-
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF);
- codegen.opcodes.push_back(res);
- int jump_success_pos2 = codegen.opcodes.size();
- codegen.opcodes.push_back(0);
-
- codegen.alloc_stack(p_stack_level); //it will be used..
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_FALSE);
- codegen.opcodes.push_back(p_stack_level | GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP);
- codegen.opcodes.push_back(codegen.opcodes.size() + 3);
- codegen.opcodes.write[jump_success_pos] = codegen.opcodes.size();
- codegen.opcodes.write[jump_success_pos2] = codegen.opcodes.size();
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TRUE);
- codegen.opcodes.push_back(p_stack_level | GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
- return p_stack_level | GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS;
-
} break;
case GDScriptParser::BinaryOpNode::OP_TYPE_TEST: {
- int slevel = p_stack_level;
-
- int src_address_a = _parse_expression(codegen, binary->left_operand, slevel);
- if (src_address_a < 0) {
- return -1;
- }
+ GDScriptCodeGenerator::Address operand = _parse_expression(codegen, r_error, binary->left_operand);
- if (src_address_a & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) {
- slevel++; //uses stack for return, increase stack
- }
-
- int src_address_b = -1;
- bool builtin = false;
if (binary->right_operand->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<const GDScriptParser::IdentifierNode *>(binary->right_operand)->name) != Variant::VARIANT_MAX) {
- // `is` with builtin type
- builtin = true;
- src_address_b = (int)GDScriptParser::get_builtin_type(static_cast<const GDScriptParser::IdentifierNode *>(binary->right_operand)->name);
+ // `is` with builtin type)
+ Variant::Type type = GDScriptParser::get_builtin_type(static_cast<const GDScriptParser::IdentifierNode *>(binary->right_operand)->name);
+ gen->write_type_test_builtin(result, operand, type);
} else {
- src_address_b = _parse_expression(codegen, binary->right_operand, slevel);
- if (src_address_b < 0) {
- return -1;
+ GDScriptCodeGenerator::Address type = _parse_expression(codegen, r_error, binary->right_operand);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
+ }
+ gen->write_type_test(result, operand, type);
+ if (type.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
}
}
+ } break;
+ default: {
+ GDScriptCodeGenerator::Address left_operand = _parse_expression(codegen, r_error, binary->left_operand);
+ GDScriptCodeGenerator::Address right_operand = _parse_expression(codegen, r_error, binary->right_operand);
- codegen.opcodes.push_back(builtin ? GDScriptFunction::OPCODE_IS_BUILTIN : GDScriptFunction::OPCODE_EXTENDS_TEST); // perform operator
- codegen.opcodes.push_back(src_address_a); // argument 1
- codegen.opcodes.push_back(src_address_b); // argument 2 (unary only takes one parameter)
+ gen->write_operator(result, binary->variant_op, left_operand, right_operand);
- } break;
- case GDScriptParser::BinaryOpNode::OP_CONTENT_TEST: {
- if (!_create_binary_operator(codegen, binary, Variant::OP_IN, p_stack_level)) {
- return -1;
- }
- } break;
- case GDScriptParser::BinaryOpNode::OP_COMP_EQUAL: {
- if (!_create_binary_operator(codegen, binary, Variant::OP_EQUAL, p_stack_level)) {
- return -1;
- }
- } break;
- case GDScriptParser::BinaryOpNode::OP_COMP_NOT_EQUAL: {
- if (!_create_binary_operator(codegen, binary, Variant::OP_NOT_EQUAL, p_stack_level)) {
- return -1;
- }
- } break;
- case GDScriptParser::BinaryOpNode::OP_COMP_LESS: {
- if (!_create_binary_operator(codegen, binary, Variant::OP_LESS, p_stack_level)) {
- return -1;
- }
- } break;
- case GDScriptParser::BinaryOpNode::OP_COMP_LESS_EQUAL: {
- if (!_create_binary_operator(codegen, binary, Variant::OP_LESS_EQUAL, p_stack_level)) {
- return -1;
- }
- } break;
- case GDScriptParser::BinaryOpNode::OP_COMP_GREATER: {
- if (!_create_binary_operator(codegen, binary, Variant::OP_GREATER, p_stack_level)) {
- return -1;
- }
- } break;
- case GDScriptParser::BinaryOpNode::OP_COMP_GREATER_EQUAL: {
- if (!_create_binary_operator(codegen, binary, Variant::OP_GREATER_EQUAL, p_stack_level)) {
- return -1;
- }
- } break;
- case GDScriptParser::BinaryOpNode::OP_ADDITION: {
- if (!_create_binary_operator(codegen, binary, Variant::OP_ADD, p_stack_level)) {
- return -1;
- }
- } break;
- case GDScriptParser::BinaryOpNode::OP_SUBTRACTION: {
- if (!_create_binary_operator(codegen, binary, Variant::OP_SUBTRACT, p_stack_level)) {
- return -1;
- }
- } break;
- case GDScriptParser::BinaryOpNode::OP_MULTIPLICATION: {
- if (!_create_binary_operator(codegen, binary, Variant::OP_MULTIPLY, p_stack_level)) {
- return -1;
- }
- } break;
- case GDScriptParser::BinaryOpNode::OP_DIVISION: {
- if (!_create_binary_operator(codegen, binary, Variant::OP_DIVIDE, p_stack_level)) {
- return -1;
+ if (right_operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
}
- } break;
- case GDScriptParser::BinaryOpNode::OP_MODULO: {
- if (!_create_binary_operator(codegen, binary, Variant::OP_MODULE, p_stack_level)) {
- return -1;
+ if (left_operand.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
}
- } break;
- case GDScriptParser::BinaryOpNode::OP_BIT_AND: {
- if (!_create_binary_operator(codegen, binary, Variant::OP_BIT_AND, p_stack_level)) {
- return -1;
- }
- } break;
- case GDScriptParser::BinaryOpNode::OP_BIT_OR: {
- if (!_create_binary_operator(codegen, binary, Variant::OP_BIT_OR, p_stack_level)) {
- return -1;
- }
- } break;
- case GDScriptParser::BinaryOpNode::OP_BIT_XOR: {
- if (!_create_binary_operator(codegen, binary, Variant::OP_BIT_XOR, p_stack_level)) {
- return -1;
- }
- } break;
- //shift
- case GDScriptParser::BinaryOpNode::OP_BIT_LEFT_SHIFT: {
- if (!_create_binary_operator(codegen, binary, Variant::OP_SHIFT_LEFT, p_stack_level)) {
- return -1;
- }
- } break;
- case GDScriptParser::BinaryOpNode::OP_BIT_RIGHT_SHIFT: {
- if (!_create_binary_operator(codegen, binary, Variant::OP_SHIFT_RIGHT, p_stack_level)) {
- return -1;
- }
- } break;
+ }
}
- OPERATOR_RETURN;
+ return result;
} break;
- // ternary operators
case GDScriptParser::Node::TERNARY_OPERATOR: {
- // x IF a ELSE y operator with early out on failure
-
+ // x IF a ELSE y operator with early out on failure.
const GDScriptParser::TernaryOpNode *ternary = static_cast<const GDScriptParser::TernaryOpNode *>(p_expression);
- int res = _parse_expression(codegen, ternary->condition, p_stack_level);
- if (res < 0) {
- return res;
- }
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF_NOT);
- codegen.opcodes.push_back(res);
- int jump_fail_pos = codegen.opcodes.size();
- codegen.opcodes.push_back(0);
+ GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(ternary->get_datatype()));
- res = _parse_expression(codegen, ternary->true_expr, p_stack_level);
- if (res < 0) {
- return res;
- }
+ gen->write_start_ternary(result);
- codegen.alloc_stack(p_stack_level); //it will be used..
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN);
- codegen.opcodes.push_back(p_stack_level | GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
- codegen.opcodes.push_back(res);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP);
- int jump_past_pos = codegen.opcodes.size();
- codegen.opcodes.push_back(0);
+ GDScriptCodeGenerator::Address condition = _parse_expression(codegen, r_error, ternary->condition);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
+ }
+ gen->write_ternary_condition(condition);
- codegen.opcodes.write[jump_fail_pos] = codegen.opcodes.size();
- res = _parse_expression(codegen, ternary->false_expr, p_stack_level);
- if (res < 0) {
- return res;
+ if (condition.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
}
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN);
- codegen.opcodes.push_back(p_stack_level | GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
- codegen.opcodes.push_back(res);
+ GDScriptCodeGenerator::Address true_expr = _parse_expression(codegen, r_error, ternary->true_expr);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
+ }
+ gen->write_ternary_true_expr(true_expr);
+ if (true_expr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
- codegen.opcodes.write[jump_past_pos] = codegen.opcodes.size();
+ GDScriptCodeGenerator::Address false_expr = _parse_expression(codegen, r_error, ternary->false_expr);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
+ }
+ gen->write_ternary_false_expr(false_expr);
+ if (false_expr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
- return p_stack_level | GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS;
+ gen->write_end_ternary();
+ return result;
} break;
- //assignment operators
case GDScriptParser::Node::ASSIGNMENT: {
const GDScriptParser::AssignmentNode *assignment = static_cast<const GDScriptParser::AssignmentNode *>(p_expression);
@@ -1186,20 +720,16 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
// SET (chained) MODE!
const GDScriptParser::SubscriptNode *subscript = static_cast<GDScriptParser::SubscriptNode *>(assignment->assignee);
#ifdef DEBUG_ENABLED
- if (subscript->is_attribute) {
- if (subscript->base->type == GDScriptParser::Node::SELF && codegen.script) {
- const Map<StringName, GDScript::MemberInfo>::Element *MI = codegen.script->member_indices.find(subscript->attribute->name);
- if (MI && MI->get().setter == codegen.function_name) {
- String n = subscript->attribute->name;
- _set_error("Must use '" + n + "' instead of 'self." + n + "' in setter.", subscript);
- return -1;
- }
+ if (subscript->is_attribute && subscript->base->type == GDScriptParser::Node::SELF && codegen.script) {
+ const Map<StringName, GDScript::MemberInfo>::Element *MI = codegen.script->member_indices.find(subscript->attribute->name);
+ if (MI && MI->get().setter == codegen.function_name) {
+ String n = subscript->attribute->name;
+ _set_error("Must use '" + n + "' instead of 'self." + n + "' in setter.", subscript);
+ r_error = ERR_COMPILATION_FAILED;
+ return GDScriptCodeGenerator::Address();
}
}
#endif
-
- int slevel = p_stack_level;
-
/* Find chain of sets */
StringName assign_property;
@@ -1207,13 +737,12 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
List<const GDScriptParser::SubscriptNode *> chain;
{
- //create get/set chain
+ // Create get/set chain.
const GDScriptParser::SubscriptNode *n = subscript;
while (true) {
chain.push_back(n);
-
if (n->base->type != GDScriptParser::Node::SUBSCRIPT) {
- //check for a built-in property
+ // Check for a built-in property.
if (n->base->type == GDScriptParser::Node::IDENTIFIER) {
GDScriptParser::IdentifierNode *identifier = static_cast<GDScriptParser::IdentifierNode *>(n->base);
if (_is_class_member_property(codegen, identifier->name)) {
@@ -1228,366 +757,396 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
/* Chain of gets */
- //get at (potential) root stack pos, so it can be returned
- int prev_pos = _parse_expression(codegen, chain.back()->get()->base, slevel);
- if (prev_pos < 0) {
- return prev_pos;
+ // Get at (potential) root stack pos, so it can be returned.
+ GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, chain.back()->get()->base);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
}
- int retval = prev_pos;
- if (retval & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) {
- slevel++;
- codegen.alloc_stack(slevel);
- }
+ GDScriptCodeGenerator::Address prev_base = base;
- Vector<int> setchain;
+ struct ChainInfo {
+ bool is_named = false;
+ GDScriptCodeGenerator::Address base;
+ GDScriptCodeGenerator::Address key;
+ StringName name;
+ };
- if (assign_property != StringName()) {
- // recover and assign at the end, this allows stuff like
- // position.x+=2.0
- // in Node2D
- setchain.push_back(prev_pos);
- setchain.push_back(codegen.get_name_map_pos(assign_property));
- setchain.push_back(GDScriptFunction::OPCODE_SET_MEMBER);
- }
+ List<ChainInfo> set_chain;
for (List<const GDScriptParser::SubscriptNode *>::Element *E = chain.back(); E; E = E->prev()) {
- if (E == chain.front()) { //ignore first
+ if (E == chain.front()) {
+ // Skip the main subscript, since we'll assign to that.
break;
}
-
const GDScriptParser::SubscriptNode *subscript_elem = E->get();
- int key_idx;
+ GDScriptCodeGenerator::Address value = codegen.add_temporary(_gdtype_from_datatype(subscript_elem->get_datatype()));
+ GDScriptCodeGenerator::Address key;
+ StringName name;
if (subscript_elem->is_attribute) {
- key_idx = codegen.get_name_map_pos(subscript_elem->attribute->name);
- //printf("named key %x\n",key_idx);
-
+ name = subscript_elem->attribute->name;
+ gen->write_get_named(value, name, prev_base);
} else {
- if (prev_pos & (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS)) {
- slevel++;
- codegen.alloc_stack(slevel);
+ key = _parse_expression(codegen, r_error, subscript_elem->index);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
}
-
- GDScriptParser::ExpressionNode *key = subscript_elem->index;
- key_idx = _parse_expression(codegen, key, slevel);
- //printf("expr key %x\n",key_idx);
-
- //stack was raised here if retval was stack but..
+ gen->write_get(value, key, prev_base);
}
- if (key_idx < 0) { //error
- return key_idx;
- }
-
- codegen.opcodes.push_back(subscript_elem->is_attribute ? GDScriptFunction::OPCODE_GET_NAMED : GDScriptFunction::OPCODE_GET);
- codegen.opcodes.push_back(prev_pos);
- codegen.opcodes.push_back(key_idx);
- slevel++;
- codegen.alloc_stack(slevel);
- int dst_pos = (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) | slevel;
-
- codegen.opcodes.push_back(dst_pos);
-
- //add in reverse order, since it will be reverted
-
- setchain.push_back(dst_pos);
- setchain.push_back(key_idx);
- setchain.push_back(prev_pos);
- setchain.push_back(subscript_elem->is_attribute ? GDScriptFunction::OPCODE_SET_NAMED : GDScriptFunction::OPCODE_SET);
-
- prev_pos = dst_pos;
+ // Store base and key for setting it back later.
+ set_chain.push_front({ subscript_elem->is_attribute, prev_base, key, name }); // Push to front to invert the list.
+ prev_base = value;
}
- setchain.invert();
-
- int set_index;
-
+ // Get value to assign.
+ GDScriptCodeGenerator::Address assigned = _parse_expression(codegen, r_error, assignment->assigned_value);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
+ }
+ // Get the key if needed.
+ GDScriptCodeGenerator::Address key;
+ StringName name;
if (subscript->is_attribute) {
- set_index = codegen.get_name_map_pos(subscript->attribute->name);
+ name = subscript->attribute->name;
} else {
- set_index = _parse_expression(codegen, subscript->index, slevel + 1);
+ key = _parse_expression(codegen, r_error, subscript->index);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
+ }
}
- if (set_index < 0) { //error
- return set_index;
+ // Perform operator if any.
+ if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
+ GDScriptCodeGenerator::Address value = codegen.add_temporary();
+ if (subscript->is_attribute) {
+ gen->write_get_named(value, name, prev_base);
+ } else {
+ gen->write_get(value, key, prev_base);
+ }
+ gen->write_operator(value, assignment->variant_op, value, assigned);
+ if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
+ assigned = value;
}
- if (set_index & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) {
- slevel++;
- codegen.alloc_stack(slevel);
+ // Perform assignment.
+ if (subscript->is_attribute) {
+ gen->write_set_named(prev_base, name, assigned);
+ } else {
+ gen->write_set(prev_base, key, assigned);
}
-
- int set_value = _parse_assign_right_expression(codegen, assignment, slevel + 1, subscript->is_attribute ? 0 : set_index);
- if (set_value < 0) { //error
- return set_value;
+ if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
}
- codegen.opcodes.push_back(subscript->is_attribute ? GDScriptFunction::OPCODE_SET_NAMED : GDScriptFunction::OPCODE_SET);
- codegen.opcodes.push_back(prev_pos);
- codegen.opcodes.push_back(set_index);
- codegen.opcodes.push_back(set_value);
+ assigned = prev_base;
- for (int i = 0; i < setchain.size(); i++) {
- codegen.opcodes.push_back(setchain[i]);
+ // Set back the values into their bases.
+ for (List<ChainInfo>::Element *E = set_chain.front(); E; E = E->next()) {
+ const ChainInfo &info = E->get();
+ if (!info.is_named) {
+ gen->write_set(info.base, info.key, assigned);
+ if (info.key.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
+ } else {
+ gen->write_set_named(info.base, info.name, assigned);
+ }
+ if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
+ assigned = info.base;
}
- return retval;
+ // If this is a local member, also assign to it.
+ // This allow things like: position.x += 2.0
+ if (assign_property != StringName()) {
+ gen->write_set_member(assigned, assign_property);
+ }
+ if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
} else if (assignment->assignee->type == GDScriptParser::Node::IDENTIFIER && _is_class_member_property(codegen, static_cast<GDScriptParser::IdentifierNode *>(assignment->assignee)->name)) {
- //assignment to member property
-
- int slevel = p_stack_level;
-
- int src_address = _parse_assign_right_expression(codegen, assignment, slevel);
- if (src_address < 0) {
- return -1;
+ // Assignment to member property.
+ GDScriptCodeGenerator::Address assigned = _parse_expression(codegen, r_error, assignment->assigned_value);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
}
+ GDScriptCodeGenerator::Address assign_temp = assigned;
StringName name = static_cast<GDScriptParser::IdentifierNode *>(assignment->assignee)->name;
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_SET_MEMBER);
- codegen.opcodes.push_back(codegen.get_name_map_pos(name));
- codegen.opcodes.push_back(src_address);
+ if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
+ GDScriptCodeGenerator::Address member = codegen.add_temporary();
+ gen->write_get_member(member, name);
+ gen->write_operator(assigned, assignment->variant_op, member, assigned);
+ gen->pop_temporary();
+ }
- return GDScriptFunction::ADDR_TYPE_NIL << GDScriptFunction::ADDR_BITS;
- } else {
- //REGULAR ASSIGNMENT MODE!!
+ gen->write_set_member(assigned, name);
- int slevel = p_stack_level;
- int dst_address_a = -1;
+ if (assign_temp.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
+ } else {
+ // Regular assignment.
+ GDScriptCodeGenerator::Address target;
bool has_setter = false;
bool is_in_setter = false;
StringName setter_function;
if (assignment->assignee->type == GDScriptParser::Node::IDENTIFIER) {
StringName var_name = static_cast<const GDScriptParser::IdentifierNode *>(assignment->assignee)->name;
- if (!codegen.stack_identifiers.has(var_name) && codegen.script->member_indices.has(var_name)) {
+ if (!codegen.locals.has(var_name) && codegen.script->member_indices.has(var_name)) {
setter_function = codegen.script->member_indices[var_name].setter;
if (setter_function != StringName()) {
has_setter = true;
is_in_setter = setter_function == codegen.function_name;
- dst_address_a = codegen.script->member_indices[var_name].index;
+ target.mode = GDScriptCodeGenerator::Address::MEMBER;
+ target.address = codegen.script->member_indices[var_name].index;
}
}
}
if (has_setter) {
- if (is_in_setter) {
- // Use direct member access.
- dst_address_a |= GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS;
- } else {
+ if (!is_in_setter) {
// Store stack slot for the temp value.
- dst_address_a = slevel++;
- codegen.alloc_stack(slevel);
- dst_address_a |= GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS;
+ target = codegen.add_temporary(_gdtype_from_datatype(assignment->assignee->get_datatype()));
}
} else {
- dst_address_a = _parse_expression(codegen, assignment->assignee, slevel);
- if (dst_address_a < 0) {
- return -1;
+ target = _parse_expression(codegen, r_error, assignment->assignee);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
}
+ }
- if (dst_address_a & GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS) {
- slevel++;
- codegen.alloc_stack(slevel);
- }
+ GDScriptCodeGenerator::Address assigned = _parse_expression(codegen, r_error, assignment->assigned_value);
+ GDScriptCodeGenerator::Address op_result;
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
}
- int src_address_b = _parse_assign_right_expression(codegen, assignment, slevel);
- if (src_address_b < 0) {
- return -1;
+ if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
+ // Perform operation.
+ op_result = codegen.add_temporary();
+ gen->write_operator(op_result, assignment->variant_op, target, assigned);
+ } else {
+ op_result = assigned;
+ assigned = GDScriptCodeGenerator::Address();
}
GDScriptDataType assign_type = _gdtype_from_datatype(assignment->assignee->get_datatype());
if (has_setter && !is_in_setter) {
// Call setter.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_CALL);
- codegen.opcodes.push_back(1); // Argument count.
- codegen.opcodes.push_back(GDScriptFunction::ADDR_TYPE_SELF << GDScriptFunction::ADDR_BITS); // Base (self).
- codegen.opcodes.push_back(codegen.get_name_map_pos(setter_function)); // Method name.
- codegen.opcodes.push_back(dst_address_a); // Argument.
- codegen.opcodes.push_back(dst_address_a); // Result address (won't be used here).
- codegen.alloc_call(1);
- } else if (!_generate_typed_assign(codegen, src_address_b, dst_address_a, assign_type, assignment->assigned_value->get_datatype())) {
- return -1;
+ Vector<GDScriptCodeGenerator::Address> args;
+ args.push_back(op_result);
+ gen->write_call(GDScriptCodeGenerator::Address(), GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), setter_function, args);
+ } else {
+ // Just assign.
+ gen->write_assign(target, op_result);
}
- return dst_address_a; //if anything, returns wathever was assigned or correct stack position
+ if (op_result.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
+ if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
+ if (target.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
}
+ return GDScriptCodeGenerator::Address(); // Assignment does not return a value.
} break;
-#undef OPERATOR_RETURN
- //TYPE_TYPE,
default: {
- ERR_FAIL_V_MSG(-1, "Bug in bytecode compiler, unexpected node in parse tree while parsing expression."); //unreachable code
+ ERR_FAIL_V_MSG(GDScriptCodeGenerator::Address(), "Bug in bytecode compiler, unexpected node in parse tree while parsing expression."); // Unreachable code.
} break;
}
}
-Error GDScriptCompiler::_parse_match_pattern(CodeGen &codegen, const GDScriptParser::PatternNode *p_pattern, int p_stack_level, int p_value_addr, int p_type_addr, int &r_bound_variables, Vector<int> &r_patch_addresses, Vector<int> &r_block_patch_address) {
- // TODO: Many "repeated" code here that could be abstracted. This compiler is going away when new VM arrives though, so...
+GDScriptCodeGenerator::Address GDScriptCompiler::_parse_match_pattern(CodeGen &codegen, Error &r_error, const GDScriptParser::PatternNode *p_pattern, const GDScriptCodeGenerator::Address &p_value_addr, const GDScriptCodeGenerator::Address &p_type_addr, const GDScriptCodeGenerator::Address &p_previous_test, bool p_is_first, bool p_is_nested) {
switch (p_pattern->pattern_type) {
case GDScriptParser::PatternNode::PT_LITERAL: {
+ if (p_is_nested) {
+ codegen.generator->write_and_left_operand(p_previous_test);
+ } else if (!p_is_first) {
+ codegen.generator->write_or_left_operand(p_previous_test);
+ }
+
// Get literal type into constant map.
- int literal_type_addr = -1;
- if (!codegen.constant_map.has((int)p_pattern->literal->value.get_type())) {
- literal_type_addr = codegen.constant_map.size();
- codegen.constant_map[(int)p_pattern->literal->value.get_type()] = literal_type_addr;
+ GDScriptCodeGenerator::Address literal_type_addr = codegen.add_constant((int)p_pattern->literal->value.get_type());
- } else {
- literal_type_addr = codegen.constant_map[(int)p_pattern->literal->value.get_type()];
- }
- literal_type_addr |= GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS;
+ // Equality is always a boolean.
+ GDScriptDataType equality_type;
+ equality_type.has_type = true;
+ equality_type.kind = GDScriptDataType::BUILTIN;
+ equality_type.builtin_type = Variant::BOOL;
// Check type equality.
- int equality_addr = p_stack_level++;
- equality_addr |= GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS;
- codegen.alloc_stack(p_stack_level);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_OPERATOR);
- codegen.opcodes.push_back(Variant::OP_EQUAL);
- codegen.opcodes.push_back(p_type_addr);
- codegen.opcodes.push_back(literal_type_addr);
- codegen.opcodes.push_back(equality_addr); // Address to result.
-
- // Jump away if not the same type.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF_NOT);
- codegen.opcodes.push_back(equality_addr);
- r_patch_addresses.push_back(codegen.opcodes.size());
- codegen.opcodes.push_back(0); // Will be replaced.
+ GDScriptCodeGenerator::Address type_equality_addr = codegen.add_temporary(equality_type);
+ codegen.generator->write_operator(type_equality_addr, Variant::OP_EQUAL, p_type_addr, literal_type_addr);
+ codegen.generator->write_and_left_operand(type_equality_addr);
// Get literal.
- int literal_addr = _parse_expression(codegen, p_pattern->literal, p_stack_level);
+ GDScriptCodeGenerator::Address literal_addr = _parse_expression(codegen, r_error, p_pattern->literal);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
+ }
// Check value equality.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_OPERATOR);
- codegen.opcodes.push_back(Variant::OP_EQUAL);
- codegen.opcodes.push_back(p_value_addr);
- codegen.opcodes.push_back(literal_addr);
- codegen.opcodes.push_back(equality_addr); // Address to result.
-
- // Jump away if doesn't match.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF_NOT);
- codegen.opcodes.push_back(equality_addr);
- r_patch_addresses.push_back(codegen.opcodes.size());
- codegen.opcodes.push_back(0); // Will be replaced.
-
- // Jump to the actual block since it matches. This is needed to take multi-pattern into account.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP);
- r_block_patch_address.push_back(codegen.opcodes.size());
- codegen.opcodes.push_back(0); // Will be replaced.
+ GDScriptCodeGenerator::Address equality_addr = codegen.add_temporary(equality_type);
+ codegen.generator->write_operator(equality_addr, Variant::OP_EQUAL, p_value_addr, literal_addr);
+ codegen.generator->write_and_right_operand(equality_addr);
+
+ // AND both together (reuse temporary location).
+ codegen.generator->write_end_and(type_equality_addr);
+
+ codegen.generator->pop_temporary(); // Remove equality_addr from stack.
+
+ if (literal_addr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ codegen.generator->pop_temporary();
+ }
+
+ // If this isn't the first, we need to OR with the previous pattern. If it's nested, we use AND instead.
+ if (p_is_nested) {
+ // Use the previous value as target, since we only need one temporary variable.
+ codegen.generator->write_and_right_operand(type_equality_addr);
+ codegen.generator->write_end_and(p_previous_test);
+ } else if (!p_is_first) {
+ // Use the previous value as target, since we only need one temporary variable.
+ codegen.generator->write_or_right_operand(type_equality_addr);
+ codegen.generator->write_end_or(p_previous_test);
+ } else {
+ // Just assign this value to the accumulator temporary.
+ codegen.generator->write_assign(p_previous_test, type_equality_addr);
+ }
+ codegen.generator->pop_temporary(); // Remove type_equality_addr.
+
+ return p_previous_test;
} break;
case GDScriptParser::PatternNode::PT_EXPRESSION: {
+ if (p_is_nested) {
+ codegen.generator->write_and_left_operand(p_previous_test);
+ } else if (!p_is_first) {
+ codegen.generator->write_or_left_operand(p_previous_test);
+ }
+ // Create the result temps first since it's the last to go away.
+ GDScriptCodeGenerator::Address result_addr = codegen.add_temporary();
+ GDScriptCodeGenerator::Address equality_test_addr = codegen.add_temporary();
+
// Evaluate expression.
- int expr_addr = _parse_expression(codegen, p_pattern->expression, p_stack_level);
- if ((expr_addr >> GDScriptFunction::ADDR_BITS & GDScriptFunction::ADDR_TYPE_STACK) == GDScriptFunction::ADDR_TYPE_STACK) {
- p_stack_level++;
- codegen.alloc_stack(p_stack_level);
+ GDScriptCodeGenerator::Address expr_addr;
+ expr_addr = _parse_expression(codegen, r_error, p_pattern->expression);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
}
// Evaluate expression type.
- int expr_type_addr = p_stack_level++;
- expr_type_addr |= GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS;
- codegen.alloc_stack(p_stack_level);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_CALL_BUILT_IN);
- codegen.opcodes.push_back(GDScriptFunctions::TYPE_OF);
- codegen.opcodes.push_back(1); // One argument.
- codegen.opcodes.push_back(expr_addr); // Argument is the value we want to test.
- codegen.opcodes.push_back(expr_type_addr); // Address to result.
+ Vector<GDScriptCodeGenerator::Address> typeof_args;
+ typeof_args.push_back(expr_addr);
+ codegen.generator->write_call_builtin(result_addr, GDScriptFunctions::TYPE_OF, typeof_args);
// Check type equality.
- int equality_addr = p_stack_level++;
- equality_addr |= GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS;
- codegen.alloc_stack(p_stack_level);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_OPERATOR);
- codegen.opcodes.push_back(Variant::OP_EQUAL);
- codegen.opcodes.push_back(p_type_addr);
- codegen.opcodes.push_back(expr_type_addr);
- codegen.opcodes.push_back(equality_addr); // Address to result.
-
- // Jump away if not the same type.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF_NOT);
- codegen.opcodes.push_back(equality_addr);
- r_patch_addresses.push_back(codegen.opcodes.size());
- codegen.opcodes.push_back(0); // Will be replaced.
+ codegen.generator->write_operator(result_addr, Variant::OP_EQUAL, p_type_addr, result_addr);
+ codegen.generator->write_and_left_operand(result_addr);
// Check value equality.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_OPERATOR);
- codegen.opcodes.push_back(Variant::OP_EQUAL);
- codegen.opcodes.push_back(p_value_addr);
- codegen.opcodes.push_back(expr_addr);
- codegen.opcodes.push_back(equality_addr); // Address to result.
-
- // Jump away if doesn't match.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF_NOT);
- codegen.opcodes.push_back(equality_addr);
- r_patch_addresses.push_back(codegen.opcodes.size());
- codegen.opcodes.push_back(0); // Will be replaced.
-
- // Jump to the actual block since it matches. This is needed to take multi-pattern into account.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP);
- r_block_patch_address.push_back(codegen.opcodes.size());
- codegen.opcodes.push_back(0); // Will be replaced.
- } break;
- case GDScriptParser::PatternNode::PT_BIND: {
- // Create new stack variable.
- int bind_addr = p_stack_level | (GDScriptFunction::ADDR_TYPE_STACK_VARIABLE << GDScriptFunction::ADDR_BITS);
- codegen.add_stack_identifier(p_pattern->bind->name, p_stack_level++);
- codegen.alloc_stack(p_stack_level);
- r_bound_variables++;
+ codegen.generator->write_operator(result_addr, Variant::OP_EQUAL, p_value_addr, expr_addr);
+ codegen.generator->write_and_right_operand(equality_test_addr);
- // Assign value to bound variable.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN);
- codegen.opcodes.push_back(bind_addr); // Destination.
- codegen.opcodes.push_back(p_value_addr); // Source.
- // Not need to block jump because bind happens only once.
+ // AND both type and value equality.
+ codegen.generator->write_end_and(result_addr);
+
+ // We don't need the expression temporary anymore.
+ if (expr_addr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ codegen.generator->pop_temporary();
+ }
+ codegen.generator->pop_temporary(); // Remove type equality temporary.
+
+ // If this isn't the first, we need to OR with the previous pattern. If it's nested, we use AND instead.
+ if (p_is_nested) {
+ // Use the previous value as target, since we only need one temporary variable.
+ codegen.generator->write_and_right_operand(result_addr);
+ codegen.generator->write_end_and(p_previous_test);
+ } else if (!p_is_first) {
+ // Use the previous value as target, since we only need one temporary variable.
+ codegen.generator->write_or_right_operand(result_addr);
+ codegen.generator->write_end_or(p_previous_test);
+ } else {
+ // Just assign this value to the accumulator temporary.
+ codegen.generator->write_assign(p_previous_test, result_addr);
+ }
+ codegen.generator->pop_temporary(); // Remove temp result addr.
+
+ return p_previous_test;
} break;
case GDScriptParser::PatternNode::PT_ARRAY: {
- int slevel = p_stack_level;
-
+ if (p_is_nested) {
+ codegen.generator->write_and_left_operand(p_previous_test);
+ } else if (!p_is_first) {
+ codegen.generator->write_or_left_operand(p_previous_test);
+ }
// Get array type into constant map.
- int array_type_addr = codegen.get_constant_pos(Variant::ARRAY);
+ GDScriptCodeGenerator::Address array_type_addr = codegen.add_constant((int)Variant::ARRAY);
+
+ // Equality is always a boolean.
+ GDScriptDataType temp_type;
+ temp_type.has_type = true;
+ temp_type.kind = GDScriptDataType::BUILTIN;
+ temp_type.builtin_type = Variant::BOOL;
// Check type equality.
- int equality_addr = slevel++;
- equality_addr |= GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS;
- codegen.alloc_stack(slevel);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_OPERATOR);
- codegen.opcodes.push_back(Variant::OP_EQUAL);
- codegen.opcodes.push_back(p_type_addr);
- codegen.opcodes.push_back(array_type_addr);
- codegen.opcodes.push_back(equality_addr); // Address to result.
-
- // Jump away if not the same type.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF_NOT);
- codegen.opcodes.push_back(equality_addr);
- r_patch_addresses.push_back(codegen.opcodes.size());
- codegen.opcodes.push_back(0); // Will be replaced.
+ GDScriptCodeGenerator::Address result_addr = codegen.add_temporary(temp_type);
+ codegen.generator->write_operator(result_addr, Variant::OP_EQUAL, p_type_addr, array_type_addr);
+ codegen.generator->write_and_left_operand(result_addr);
// Store pattern length in constant map.
- int array_length_addr = codegen.get_constant_pos(p_pattern->rest_used ? p_pattern->array.size() - 1 : p_pattern->array.size());
+ GDScriptCodeGenerator::Address array_length_addr = codegen.add_constant(p_pattern->rest_used ? p_pattern->array.size() - 1 : p_pattern->array.size());
// Get value length.
- int value_length_addr = slevel++;
- codegen.alloc_stack(slevel);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_CALL_BUILT_IN);
- codegen.opcodes.push_back(GDScriptFunctions::LEN);
- codegen.opcodes.push_back(1); // One argument.
- codegen.opcodes.push_back(p_value_addr); // Argument is the value we want to test.
- codegen.opcodes.push_back(value_length_addr); // Address to result.
+ temp_type.builtin_type = Variant::INT;
+ GDScriptCodeGenerator::Address value_length_addr = codegen.add_temporary(temp_type);
+ Vector<GDScriptCodeGenerator::Address> len_args;
+ len_args.push_back(p_value_addr);
+ codegen.generator->write_call_builtin(value_length_addr, GDScriptFunctions::LEN, len_args);
// Test length compatibility.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_OPERATOR);
- codegen.opcodes.push_back(p_pattern->rest_used ? Variant::OP_GREATER_EQUAL : Variant::OP_EQUAL);
- codegen.opcodes.push_back(value_length_addr);
- codegen.opcodes.push_back(array_length_addr);
- codegen.opcodes.push_back(equality_addr); // Address to result.
-
- // Jump away if length is not compatible.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF_NOT);
- codegen.opcodes.push_back(equality_addr);
- r_patch_addresses.push_back(codegen.opcodes.size());
- codegen.opcodes.push_back(0); // Will be replaced.
+ temp_type.builtin_type = Variant::BOOL;
+ GDScriptCodeGenerator::Address length_compat_addr = codegen.add_temporary(temp_type);
+ codegen.generator->write_operator(length_compat_addr, p_pattern->rest_used ? Variant::OP_GREATER_EQUAL : Variant::OP_EQUAL, value_length_addr, array_length_addr);
+ codegen.generator->write_and_right_operand(length_compat_addr);
+
+ // AND type and length check.
+ codegen.generator->write_end_and(result_addr);
+
+ // Remove length temporaries.
+ codegen.generator->pop_temporary();
+ codegen.generator->pop_temporary();
+
+ // If this isn't the first, we need to OR with the previous pattern. If it's nested, we use AND instead.
+ if (p_is_nested) {
+ // Use the previous value as target, since we only need one temporary variable.
+ codegen.generator->write_and_right_operand(result_addr);
+ codegen.generator->write_end_and(p_previous_test);
+ } else if (!p_is_first) {
+ // Use the previous value as target, since we only need one temporary variable.
+ codegen.generator->write_or_right_operand(result_addr);
+ codegen.generator->write_end_or(p_previous_test);
+ } else {
+ // Just assign this value to the accumulator temporary.
+ codegen.generator->write_assign(p_previous_test, result_addr);
+ }
+ codegen.generator->pop_temporary(); // Remove temp result addr.
+
+ // Create temporaries outside the loop so they can be reused.
+ GDScriptCodeGenerator::Address element_addr = codegen.add_temporary();
+ GDScriptCodeGenerator::Address element_type_addr = codegen.add_temporary();
+ GDScriptCodeGenerator::Address test_addr = p_previous_test;
// Evaluate element by element.
for (int i = 0; i < p_pattern->array.size(); i++) {
@@ -1596,494 +1155,461 @@ Error GDScriptCompiler::_parse_match_pattern(CodeGen &codegen, const GDScriptPar
break;
}
- int stlevel = p_stack_level;
- Vector<int> element_block_patches; // I want to internal patterns try the next element instead of going to the block.
+ // Use AND here too, as we don't want to be checking elements if previous test failed (which means this might be an invalid get).
+ codegen.generator->write_and_left_operand(test_addr);
+
// Add index to constant map.
- int index_addr = codegen.get_constant_pos(i);
+ GDScriptCodeGenerator::Address index_addr = codegen.add_constant(i);
// Get the actual element from the user-sent array.
- int element_addr = stlevel++;
- codegen.alloc_stack(stlevel);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_GET);
- codegen.opcodes.push_back(p_value_addr); // Source.
- codegen.opcodes.push_back(index_addr); // Index.
- codegen.opcodes.push_back(element_addr); // Destination.
+ codegen.generator->write_get(element_addr, index_addr, p_value_addr);
// Also get type of element.
- int element_type_addr = stlevel++;
- element_type_addr |= GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS;
- codegen.alloc_stack(stlevel);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_CALL_BUILT_IN);
- codegen.opcodes.push_back(GDScriptFunctions::TYPE_OF);
- codegen.opcodes.push_back(1); // One argument.
- codegen.opcodes.push_back(element_addr); // Argument is the value we want to test.
- codegen.opcodes.push_back(element_type_addr); // Address to result.
+ Vector<GDScriptCodeGenerator::Address> typeof_args;
+ typeof_args.push_back(element_addr);
+ codegen.generator->write_call_builtin(element_type_addr, GDScriptFunctions::TYPE_OF, typeof_args);
// Try the pattern inside the element.
- Error err = _parse_match_pattern(codegen, p_pattern->array[i], stlevel, element_addr, element_type_addr, r_bound_variables, r_patch_addresses, element_block_patches);
- if (err != OK) {
- return err;
+ test_addr = _parse_match_pattern(codegen, r_error, p_pattern->array[i], element_addr, element_type_addr, p_previous_test, false, true);
+ if (r_error != OK) {
+ return GDScriptCodeGenerator::Address();
}
- // Patch jumps to block to try the next element.
- for (int j = 0; j < element_block_patches.size(); j++) {
- codegen.opcodes.write[element_block_patches[j]] = codegen.opcodes.size();
- }
+ codegen.generator->write_and_right_operand(test_addr);
+ codegen.generator->write_end_and(test_addr);
}
+ // Remove element temporaries.
+ codegen.generator->pop_temporary();
+ codegen.generator->pop_temporary();
- // Jump to the actual block since it matches. This is needed to take multi-pattern into account.
- // Also here for the case of empty arrays.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP);
- r_block_patch_address.push_back(codegen.opcodes.size());
- codegen.opcodes.push_back(0); // Will be replaced.
+ return test_addr;
} break;
case GDScriptParser::PatternNode::PT_DICTIONARY: {
- int slevel = p_stack_level;
-
+ if (p_is_nested) {
+ codegen.generator->write_and_left_operand(p_previous_test);
+ } else if (!p_is_first) {
+ codegen.generator->write_or_left_operand(p_previous_test);
+ }
// Get dictionary type into constant map.
- int dict_type_addr = codegen.get_constant_pos(Variant::DICTIONARY);
+ GDScriptCodeGenerator::Address dict_type_addr = codegen.add_constant((int)Variant::DICTIONARY);
+
+ // Equality is always a boolean.
+ GDScriptDataType temp_type;
+ temp_type.has_type = true;
+ temp_type.kind = GDScriptDataType::BUILTIN;
+ temp_type.builtin_type = Variant::BOOL;
// Check type equality.
- int equality_addr = slevel++;
- equality_addr |= GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS;
- codegen.alloc_stack(slevel);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_OPERATOR);
- codegen.opcodes.push_back(Variant::OP_EQUAL);
- codegen.opcodes.push_back(p_type_addr);
- codegen.opcodes.push_back(dict_type_addr);
- codegen.opcodes.push_back(equality_addr); // Address to result.
-
- // Jump away if not the same type.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF_NOT);
- codegen.opcodes.push_back(equality_addr);
- r_patch_addresses.push_back(codegen.opcodes.size());
- codegen.opcodes.push_back(0); // Will be replaced.
+ GDScriptCodeGenerator::Address result_addr = codegen.add_temporary(temp_type);
+ codegen.generator->write_operator(result_addr, Variant::OP_EQUAL, p_type_addr, dict_type_addr);
+ codegen.generator->write_and_left_operand(result_addr);
// Store pattern length in constant map.
- int dict_length_addr = codegen.get_constant_pos(p_pattern->rest_used ? p_pattern->dictionary.size() - 1 : p_pattern->dictionary.size());
+ GDScriptCodeGenerator::Address dict_length_addr = codegen.add_constant(p_pattern->rest_used ? p_pattern->dictionary.size() - 1 : p_pattern->dictionary.size());
// Get user's dictionary length.
- int value_length_addr = slevel++;
- codegen.alloc_stack(slevel);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_CALL_BUILT_IN);
- codegen.opcodes.push_back(GDScriptFunctions::LEN);
- codegen.opcodes.push_back(1); // One argument.
- codegen.opcodes.push_back(p_value_addr); // Argument is the value we want to test.
- codegen.opcodes.push_back(value_length_addr); // Address to result.
+ temp_type.builtin_type = Variant::INT;
+ GDScriptCodeGenerator::Address value_length_addr = codegen.add_temporary(temp_type);
+ Vector<GDScriptCodeGenerator::Address> func_args;
+ func_args.push_back(p_value_addr);
+ codegen.generator->write_call_builtin(value_length_addr, GDScriptFunctions::LEN, func_args);
// Test length compatibility.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_OPERATOR);
- codegen.opcodes.push_back(p_pattern->rest_used ? Variant::OP_GREATER_EQUAL : Variant::OP_EQUAL);
- codegen.opcodes.push_back(value_length_addr);
- codegen.opcodes.push_back(dict_length_addr);
- codegen.opcodes.push_back(equality_addr); // Address to result.
-
- // Jump away if length is not compatible.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF_NOT);
- codegen.opcodes.push_back(equality_addr);
- r_patch_addresses.push_back(codegen.opcodes.size());
- codegen.opcodes.push_back(0); // Will be replaced.
+ temp_type.builtin_type = Variant::BOOL;
+ GDScriptCodeGenerator::Address length_compat_addr = codegen.add_temporary(temp_type);
+ codegen.generator->write_operator(length_compat_addr, p_pattern->rest_used ? Variant::OP_GREATER_EQUAL : Variant::OP_EQUAL, value_length_addr, dict_length_addr);
+ codegen.generator->write_and_right_operand(length_compat_addr);
+
+ // AND type and length check.
+ codegen.generator->write_end_and(result_addr);
+
+ // Remove length temporaries.
+ codegen.generator->pop_temporary();
+ codegen.generator->pop_temporary();
+
+ // If this isn't the first, we need to OR with the previous pattern. If it's nested, we use AND instead.
+ if (p_is_nested) {
+ // Use the previous value as target, since we only need one temporary variable.
+ codegen.generator->write_and_right_operand(result_addr);
+ codegen.generator->write_end_and(p_previous_test);
+ } else if (!p_is_first) {
+ // Use the previous value as target, since we only need one temporary variable.
+ codegen.generator->write_or_right_operand(result_addr);
+ codegen.generator->write_end_or(p_previous_test);
+ } else {
+ // Just assign this value to the accumulator temporary.
+ codegen.generator->write_assign(p_previous_test, result_addr);
+ }
+ codegen.generator->pop_temporary(); // Remove temp result addr.
+
+ // Create temporaries outside the loop so they can be reused.
+ temp_type.builtin_type = Variant::BOOL;
+ GDScriptCodeGenerator::Address test_result = codegen.add_temporary(temp_type);
+ GDScriptCodeGenerator::Address element_addr = codegen.add_temporary();
+ GDScriptCodeGenerator::Address element_type_addr = codegen.add_temporary();
+ GDScriptCodeGenerator::Address test_addr = p_previous_test;
// Evaluate element by element.
for (int i = 0; i < p_pattern->dictionary.size(); i++) {
const GDScriptParser::PatternNode::Pair &element = p_pattern->dictionary[i];
if (element.value_pattern && element.value_pattern->pattern_type == GDScriptParser::PatternNode::PT_REST) {
// Ignore rest pattern.
- continue;
+ break;
}
- int stlevel = p_stack_level;
- Vector<int> element_block_patches; // I want to internal patterns try the next element instead of going to the block.
+
+ // Use AND here too, as we don't want to be checking elements if previous test failed (which means this might be an invalid get).
+ codegen.generator->write_and_left_operand(test_addr);
// Get the pattern key.
- int pattern_key_addr = _parse_expression(codegen, element.key, stlevel);
- if (pattern_key_addr < 0) {
- return ERR_PARSE_ERROR;
- }
- if ((pattern_key_addr >> GDScriptFunction::ADDR_BITS & GDScriptFunction::ADDR_TYPE_STACK) == GDScriptFunction::ADDR_TYPE_STACK) {
- stlevel++;
- codegen.alloc_stack(stlevel);
+ GDScriptCodeGenerator::Address pattern_key_addr = _parse_expression(codegen, r_error, element.key);
+ if (r_error) {
+ return GDScriptCodeGenerator::Address();
}
- // Create stack slot for test result.
- int test_result = stlevel++;
- test_result |= GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS;
- codegen.alloc_stack(stlevel);
-
- // Check if pattern key exists in user's dictionary.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_CALL_RETURN);
- codegen.opcodes.push_back(1); // Argument count.
- codegen.opcodes.push_back(p_value_addr); // Base (user dictionary).
- codegen.opcodes.push_back(codegen.get_name_map_pos("has")); // Function name.
- codegen.opcodes.push_back(pattern_key_addr); // Argument (pattern key).
- codegen.opcodes.push_back(test_result); // Return address.
-
- // Jump away if key doesn't exist.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF_NOT);
- codegen.opcodes.push_back(test_result);
- r_patch_addresses.push_back(codegen.opcodes.size());
- codegen.opcodes.push_back(0); // Will be replaced.
+ // Check if pattern key exists in user's dictionary. This will be AND-ed with next result.
+ func_args.clear();
+ func_args.push_back(pattern_key_addr);
+ codegen.generator->write_call(test_result, p_value_addr, "has", func_args);
if (element.value_pattern != nullptr) {
+ // Use AND here too, as we don't want to be checking elements if previous test failed (which means this might be an invalid get).
+ codegen.generator->write_and_left_operand(test_result);
+
// Get actual value from user dictionary.
- int value_addr = stlevel++;
- codegen.alloc_stack(stlevel);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_GET);
- codegen.opcodes.push_back(p_value_addr); // Source.
- codegen.opcodes.push_back(pattern_key_addr); // Index.
- codegen.opcodes.push_back(value_addr); // Destination.
+ codegen.generator->write_get(element_addr, pattern_key_addr, p_value_addr);
// Also get type of value.
- int value_type_addr = stlevel++;
- value_type_addr |= GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS;
- codegen.alloc_stack(stlevel);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_CALL_BUILT_IN);
- codegen.opcodes.push_back(GDScriptFunctions::TYPE_OF);
- codegen.opcodes.push_back(1); // One argument.
- codegen.opcodes.push_back(value_addr); // Argument is the value we want to test.
- codegen.opcodes.push_back(value_type_addr); // Address to result.
+ func_args.clear();
+ func_args.push_back(element_addr);
+ codegen.generator->write_call_builtin(element_type_addr, GDScriptFunctions::TYPE_OF, func_args);
// Try the pattern inside the value.
- Error err = _parse_match_pattern(codegen, element.value_pattern, stlevel, value_addr, value_type_addr, r_bound_variables, r_patch_addresses, element_block_patches);
- if (err != OK) {
- return err;
+ test_addr = _parse_match_pattern(codegen, r_error, element.value_pattern, element_addr, element_type_addr, test_addr, false, true);
+ if (r_error != OK) {
+ return GDScriptCodeGenerator::Address();
}
+ codegen.generator->write_and_right_operand(test_addr);
+ codegen.generator->write_end_and(test_addr);
}
- // Patch jumps to block to try the next element.
- for (int j = 0; j < element_block_patches.size(); j++) {
- codegen.opcodes.write[element_block_patches[j]] = codegen.opcodes.size();
+ codegen.generator->write_and_right_operand(test_addr);
+ codegen.generator->write_end_and(test_addr);
+
+ // Remove pattern key temporary.
+ if (pattern_key_addr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ codegen.generator->pop_temporary();
}
}
- // Jump to the actual block since it matches. This is needed to take multi-pattern into account.
- // Also here for the case of empty dictionaries.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP);
- r_block_patch_address.push_back(codegen.opcodes.size());
- codegen.opcodes.push_back(0); // Will be replaced.
+ // Remove element temporaries.
+ codegen.generator->pop_temporary();
+ codegen.generator->pop_temporary();
+ codegen.generator->pop_temporary();
+ return test_addr;
} break;
case GDScriptParser::PatternNode::PT_REST:
// Do nothing.
+ return p_previous_test;
break;
+ case GDScriptParser::PatternNode::PT_BIND: {
+ if (p_is_nested) {
+ codegen.generator->write_and_left_operand(p_previous_test);
+ } else if (!p_is_first) {
+ codegen.generator->write_or_left_operand(p_previous_test);
+ }
+ // Get the bind address.
+ GDScriptCodeGenerator::Address bind = codegen.locals[p_pattern->bind->name];
+
+ // Assign value to bound variable.
+ codegen.generator->write_assign(bind, p_value_addr);
+ }
+ [[fallthrough]]; // Act like matching anything too.
case GDScriptParser::PatternNode::PT_WILDCARD:
- // This matches anything so just do the jump.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP);
- r_block_patch_address.push_back(codegen.opcodes.size());
- codegen.opcodes.push_back(0); // Will be replaced.
+ // If this is a fall through we don't want to do this again.
+ if (p_pattern->pattern_type != GDScriptParser::PatternNode::PT_BIND) {
+ if (p_is_nested) {
+ codegen.generator->write_and_left_operand(p_previous_test);
+ } else if (!p_is_first) {
+ codegen.generator->write_or_left_operand(p_previous_test);
+ }
+ }
+ // This matches anything so just do the same as `if(true)`.
+ // If this isn't the first, we need to OR with the previous pattern. If it's nested, we use AND instead.
+ if (p_is_nested) {
+ // Use the operator with the `true` constant so it works as always matching.
+ GDScriptCodeGenerator::Address constant = codegen.add_constant(true);
+ codegen.generator->write_and_right_operand(constant);
+ codegen.generator->write_end_and(p_previous_test);
+ } else if (!p_is_first) {
+ // Use the operator with the `true` constant so it works as always matching.
+ GDScriptCodeGenerator::Address constant = codegen.add_constant(true);
+ codegen.generator->write_or_right_operand(constant);
+ codegen.generator->write_end_or(p_previous_test);
+ } else {
+ // Just assign this value to the accumulator temporary.
+ codegen.generator->write_assign_true(p_previous_test);
+ }
+ return p_previous_test;
+ }
+ ERR_FAIL_V_MSG(p_previous_test, "Reaching the end of pattern compilation without matching a pattern.");
+}
+
+void GDScriptCompiler::_add_locals_in_block(CodeGen &codegen, const GDScriptParser::SuiteNode *p_block) {
+ for (int i = 0; i < p_block->locals.size(); i++) {
+ if (p_block->locals[i].type == GDScriptParser::SuiteNode::Local::PARAMETER || p_block->locals[i].type == GDScriptParser::SuiteNode::Local::FOR_VARIABLE) {
+ // Parameters are added directly from function and loop variables are declared explicitly.
+ continue;
+ }
+ codegen.add_local(p_block->locals[i].name, _gdtype_from_datatype(p_block->locals[i].get_datatype()));
}
- return OK;
}
-Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::SuiteNode *p_block, int p_stack_level, int p_break_addr, int p_continue_addr) {
- codegen.push_stack_identifiers();
- int new_identifiers = 0;
- codegen.current_line = p_block->start_line;
+Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::SuiteNode *p_block, bool p_add_locals) {
+ Error error = OK;
+ GDScriptCodeGenerator *gen = codegen.generator;
+
+ codegen.start_block();
+
+ if (p_add_locals) {
+ _add_locals_in_block(codegen, p_block);
+ }
for (int i = 0; i < p_block->statements.size(); i++) {
const GDScriptParser::Node *s = p_block->statements[i];
#ifdef DEBUG_ENABLED
// Add a newline before each statement, since the debugger needs those.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_LINE);
- codegen.opcodes.push_back(s->start_line);
- codegen.current_line = s->start_line;
+ gen->write_newline(s->start_line);
#endif
switch (s->type) {
case GDScriptParser::Node::MATCH: {
const GDScriptParser::MatchNode *match = static_cast<const GDScriptParser::MatchNode *>(s);
- int slevel = p_stack_level;
+ gen->start_match();
+ codegen.start_block();
- // First, let's save the addres of the value match.
- int temp_addr = _parse_expression(codegen, match->test, slevel);
- if (temp_addr < 0) {
- return ERR_PARSE_ERROR;
- }
- if ((temp_addr >> GDScriptFunction::ADDR_BITS & GDScriptFunction::ADDR_TYPE_STACK) == GDScriptFunction::ADDR_TYPE_STACK) {
- slevel++;
- codegen.alloc_stack(slevel);
+ // Evaluate the match expression.
+ GDScriptCodeGenerator::Address value = _parse_expression(codegen, error, match->test);
+ if (error) {
+ return error;
}
// Then, let's save the type of the value in the stack too, so we can reuse for later comparisons.
- int type_addr = slevel++;
- type_addr |= GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS;
- codegen.alloc_stack(slevel);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_CALL_BUILT_IN);
- codegen.opcodes.push_back(GDScriptFunctions::TYPE_OF);
- codegen.opcodes.push_back(1); // One argument.
- codegen.opcodes.push_back(temp_addr); // Argument is the value we want to test.
- codegen.opcodes.push_back(type_addr); // Address to result.
-
- Vector<int> patch_match_end; // Will patch the jump to the end of match.
+ GDScriptCodeGenerator::Address type = codegen.add_temporary();
+ Vector<GDScriptCodeGenerator::Address> typeof_args;
+ typeof_args.push_back(value);
+ gen->write_call_builtin(type, GDScriptFunctions::TYPE_OF, typeof_args);
// Now we can actually start testing.
// For each branch.
for (int j = 0; j < match->branches.size(); j++) {
+ if (j > 0) {
+ // Use `else` to not check the next branch after matching.
+ gen->write_else();
+ }
+
const GDScriptParser::MatchBranchNode *branch = match->branches[j];
- int bound_variables = 0;
- codegen.push_stack_identifiers(); // Create an extra block around for binds.
+ gen->start_match_branch(); // Need so lower level code can patch 'continue' jumps.
+ codegen.start_block(); // Create an extra block around for binds.
+
+ // Add locals in block before patterns, so temporaries don't use the stack address for binds.
+ _add_locals_in_block(codegen, branch->block);
#ifdef DEBUG_ENABLED
// Add a newline before each branch, since the debugger needs those.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_LINE);
- codegen.opcodes.push_back(s->start_line);
- codegen.current_line = s->start_line;
+ gen->write_newline(branch->start_line);
#endif
- Vector<int> patch_addrs; // Will patch with end of pattern to jump.
- Vector<int> block_patch_addrs; // Will patch with start of block to jump.
-
// For each pattern in branch.
+ GDScriptCodeGenerator::Address pattern_result = codegen.add_temporary();
for (int k = 0; k < branch->patterns.size(); k++) {
- if (k > 0) {
- // Patch jumps per pattern to allow for multipattern. If a pattern fails it just tries the next.
- for (int l = 0; l < patch_addrs.size(); l++) {
- codegen.opcodes.write[patch_addrs[l]] = codegen.opcodes.size();
- }
- patch_addrs.clear();
- }
- Error err = _parse_match_pattern(codegen, branch->patterns[k], slevel, temp_addr, type_addr, bound_variables, patch_addrs, block_patch_addrs);
- if (err != OK) {
- return err;
+ pattern_result = _parse_match_pattern(codegen, error, branch->patterns[k], value, type, pattern_result, k == 0, false);
+ if (error != OK) {
+ return error;
}
}
- // Patch jumps to the block.
- for (int k = 0; k < block_patch_addrs.size(); k++) {
- codegen.opcodes.write[block_patch_addrs[k]] = codegen.opcodes.size();
- }
-
- // Leave space for bound variables.
- slevel += bound_variables;
- codegen.alloc_stack(slevel);
- // Parse the branch block.
- _parse_block(codegen, branch->block, slevel, p_break_addr, p_continue_addr);
+ // Check if pattern did match.
+ gen->write_if(pattern_result);
- // Jump to end of match.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP);
- patch_match_end.push_back(codegen.opcodes.size());
- codegen.opcodes.push_back(0); // Will be patched.
+ // Remove the result from stack.
+ gen->pop_temporary();
- // Patch the addresses of last pattern to jump to the end of the branch, into the next one.
- for (int k = 0; k < patch_addrs.size(); k++) {
- codegen.opcodes.write[patch_addrs[k]] = codegen.opcodes.size();
+ // Parse the branch block.
+ error = _parse_block(codegen, branch->block, false); // Don't add locals again.
+ if (error) {
+ return error;
}
- codegen.pop_stack_identifiers(); // Get out of extra block.
+ codegen.end_block(); // Get out of extra block.
+ }
+
+ // End all nested `if`s.
+ for (int j = 0; j < match->branches.size(); j++) {
+ gen->write_endif();
}
- // Patch the addresses to jump to the end of the match statement.
- for (int j = 0; j < patch_match_end.size(); j++) {
- codegen.opcodes.write[patch_match_end[j]] = codegen.opcodes.size();
+
+ gen->pop_temporary();
+
+ if (value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ codegen.generator->pop_temporary();
}
- } break;
+ gen->end_match();
+ } break;
case GDScriptParser::Node::IF: {
const GDScriptParser::IfNode *if_n = static_cast<const GDScriptParser::IfNode *>(s);
- int ret2 = _parse_expression(codegen, if_n->condition, p_stack_level, false);
- if (ret2 < 0) {
- return ERR_PARSE_ERROR;
+ GDScriptCodeGenerator::Address condition = _parse_expression(codegen, error, if_n->condition);
+ if (error) {
+ return error;
}
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF_NOT);
- codegen.opcodes.push_back(ret2);
- int else_addr = codegen.opcodes.size();
- codegen.opcodes.push_back(0); //temporary
+ gen->write_if(condition);
+
+ if (condition.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ codegen.generator->pop_temporary();
+ }
- Error err = _parse_block(codegen, if_n->true_block, p_stack_level, p_break_addr, p_continue_addr);
- if (err) {
- return err;
+ error = _parse_block(codegen, if_n->true_block);
+ if (error) {
+ return error;
}
if (if_n->false_block) {
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP);
- int end_addr = codegen.opcodes.size();
- codegen.opcodes.push_back(0);
- codegen.opcodes.write[else_addr] = codegen.opcodes.size();
-
- Error err2 = _parse_block(codegen, if_n->false_block, p_stack_level, p_break_addr, p_continue_addr);
- if (err2) {
- return err2;
- }
+ gen->write_else();
- codegen.opcodes.write[end_addr] = codegen.opcodes.size();
- } else {
- //end without else
- codegen.opcodes.write[else_addr] = codegen.opcodes.size();
+ error = _parse_block(codegen, if_n->false_block);
+ if (error) {
+ return error;
+ }
}
+ gen->write_endif();
} break;
case GDScriptParser::Node::FOR: {
const GDScriptParser::ForNode *for_n = static_cast<const GDScriptParser::ForNode *>(s);
- int slevel = p_stack_level;
- int iter_stack_pos = slevel;
- int iterator_pos = (slevel++) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
- int counter_pos = (slevel++) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
- int container_pos = (slevel++) | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);
- codegen.alloc_stack(slevel);
-
- codegen.push_stack_identifiers();
- codegen.add_stack_identifier(for_n->variable->name, iter_stack_pos);
-
- int ret2 = _parse_expression(codegen, for_n->list, slevel, false);
- if (ret2 < 0) {
- return ERR_COMPILATION_FAILED;
- }
-
- //assign container
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN);
- codegen.opcodes.push_back(container_pos);
- codegen.opcodes.push_back(ret2);
-
- //begin loop
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ITERATE_BEGIN);
- codegen.opcodes.push_back(counter_pos);
- codegen.opcodes.push_back(container_pos);
- codegen.opcodes.push_back(codegen.opcodes.size() + 4);
- codegen.opcodes.push_back(iterator_pos);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP); //skip code for next
- codegen.opcodes.push_back(codegen.opcodes.size() + 8);
- //break loop
- int break_pos = codegen.opcodes.size();
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP); //skip code for next
- codegen.opcodes.push_back(0); //skip code for next
- //next loop
- int continue_pos = codegen.opcodes.size();
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ITERATE);
- codegen.opcodes.push_back(counter_pos);
- codegen.opcodes.push_back(container_pos);
- codegen.opcodes.push_back(break_pos);
- codegen.opcodes.push_back(iterator_pos);
-
- Error err = _parse_block(codegen, for_n->loop, slevel, break_pos, continue_pos);
- if (err) {
- return err;
- }
-
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP);
- codegen.opcodes.push_back(continue_pos);
- codegen.opcodes.write[break_pos + 1] = codegen.opcodes.size();
-
- codegen.pop_stack_identifiers();
+ codegen.start_block();
+ GDScriptCodeGenerator::Address iterator = codegen.add_local(for_n->variable->name, _gdtype_from_datatype(for_n->variable->get_datatype()));
+
+ GDScriptCodeGenerator::Address list = _parse_expression(codegen, error, for_n->list);
+ if (error) {
+ return error;
+ }
+
+ gen->write_for(iterator, list);
+
+ error = _parse_block(codegen, for_n->loop);
+ if (error) {
+ return error;
+ }
+
+ gen->write_endfor();
+
+ if (list.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ codegen.generator->pop_temporary();
+ }
+
+ codegen.end_block();
} break;
case GDScriptParser::Node::WHILE: {
const GDScriptParser::WhileNode *while_n = static_cast<const GDScriptParser::WhileNode *>(s);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP);
- codegen.opcodes.push_back(codegen.opcodes.size() + 3);
- int break_addr = codegen.opcodes.size();
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP);
- codegen.opcodes.push_back(0);
- int continue_addr = codegen.opcodes.size();
-
- int ret2 = _parse_expression(codegen, while_n->condition, p_stack_level, false);
- if (ret2 < 0) {
- return ERR_PARSE_ERROR;
+
+ gen->start_while_condition();
+
+ GDScriptCodeGenerator::Address condition = _parse_expression(codegen, error, while_n->condition);
+ if (error) {
+ return error;
}
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_IF_NOT);
- codegen.opcodes.push_back(ret2);
- codegen.opcodes.push_back(break_addr);
- Error err = _parse_block(codegen, while_n->loop, p_stack_level, break_addr, continue_addr);
- if (err) {
- return err;
+
+ gen->write_while(condition);
+
+ if (condition.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ codegen.generator->pop_temporary();
}
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP);
- codegen.opcodes.push_back(continue_addr);
- codegen.opcodes.write[break_addr + 1] = codegen.opcodes.size();
+ error = _parse_block(codegen, while_n->loop);
+ if (error) {
+ return error;
+ }
+ gen->write_endwhile();
} break;
case GDScriptParser::Node::BREAK: {
- if (p_break_addr < 0) {
- _set_error("'break'' not within loop", s);
- return ERR_COMPILATION_FAILED;
- }
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP);
- codegen.opcodes.push_back(p_break_addr);
-
+ gen->write_break();
} break;
case GDScriptParser::Node::CONTINUE: {
- if (p_continue_addr < 0) {
- _set_error("'continue' not within loop", s);
- return ERR_COMPILATION_FAILED;
+ const GDScriptParser::ContinueNode *cont = static_cast<const GDScriptParser::ContinueNode *>(s);
+ if (cont->is_for_match) {
+ gen->write_continue_match();
+ } else {
+ gen->write_continue();
}
-
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP);
- codegen.opcodes.push_back(p_continue_addr);
-
} break;
case GDScriptParser::Node::RETURN: {
const GDScriptParser::ReturnNode *return_n = static_cast<const GDScriptParser::ReturnNode *>(s);
- int ret2;
+
+ GDScriptCodeGenerator::Address return_value;
if (return_n->return_value != nullptr) {
- ret2 = _parse_expression(codegen, return_n->return_value, p_stack_level, false);
- if (ret2 < 0) {
- return ERR_PARSE_ERROR;
+ return_value = _parse_expression(codegen, error, return_n->return_value);
+ if (error) {
+ return error;
}
-
- } else {
- ret2 = GDScriptFunction::ADDR_TYPE_NIL << GDScriptFunction::ADDR_BITS;
}
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_RETURN);
- codegen.opcodes.push_back(ret2);
-
+ gen->write_return(return_value);
+ if (return_value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ codegen.generator->pop_temporary();
+ }
} break;
case GDScriptParser::Node::ASSERT: {
#ifdef DEBUG_ENABLED
- // try subblocks
-
const GDScriptParser::AssertNode *as = static_cast<const GDScriptParser::AssertNode *>(s);
- int ret2 = _parse_expression(codegen, as->condition, p_stack_level, false);
- if (ret2 < 0) {
- return ERR_PARSE_ERROR;
+ GDScriptCodeGenerator::Address condition = _parse_expression(codegen, error, as->condition);
+ if (error) {
+ return error;
}
- int message_ret = 0;
+ GDScriptCodeGenerator::Address message;
+
if (as->message) {
- message_ret = _parse_expression(codegen, as->message, p_stack_level + 1, false);
- if (message_ret < 0) {
- return ERR_PARSE_ERROR;
+ message = _parse_expression(codegen, error, as->message);
+ if (error) {
+ return error;
}
}
+ gen->write_assert(condition, message);
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSERT);
- codegen.opcodes.push_back(ret2);
- codegen.opcodes.push_back(message_ret);
+ if (condition.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ codegen.generator->pop_temporary();
+ }
+ if (message.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ codegen.generator->pop_temporary();
+ }
#endif
} break;
case GDScriptParser::Node::BREAKPOINT: {
#ifdef DEBUG_ENABLED
- // try subblocks
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_BREAKPOINT);
+ gen->write_breakpoint();
#endif
} break;
case GDScriptParser::Node::VARIABLE: {
const GDScriptParser::VariableNode *lv = static_cast<const GDScriptParser::VariableNode *>(s);
-
- // since we are using properties now for most class access, allow shadowing of class members to make user's life easier.
- //
- //if (_is_class_member_property(codegen, lv->name)) {
- // _set_error("Name for local variable '" + String(lv->name) + "' can't shadow class property of the same name.", lv);
- // return ERR_ALREADY_EXISTS;
- //}
-
- codegen.add_stack_identifier(lv->identifier->name, p_stack_level++);
- codegen.alloc_stack(p_stack_level);
- new_identifiers++;
+ // Should be already in stack when the block began.
+ GDScriptCodeGenerator::Address local = codegen.locals[lv->identifier->name];
if (lv->initializer != nullptr) {
- int dst_address = codegen.stack_identifiers[lv->identifier->name];
- dst_address |= GDScriptFunction::ADDR_TYPE_STACK_VARIABLE << GDScriptFunction::ADDR_BITS;
-
- int src_address = _parse_expression(codegen, lv->initializer, p_stack_level);
- if (src_address < 0) {
- return ERR_PARSE_ERROR;
+ GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, error, lv->initializer);
+ if (error) {
+ return error;
}
- if (!_generate_typed_assign(codegen, src_address, dst_address, _gdtype_from_datatype(lv->get_datatype()), lv->initializer->get_datatype())) {
- return ERR_PARSE_ERROR;
+ gen->write_assign(local, src_address);
+ if (src_address.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ codegen.generator->pop_temporary();
}
}
} break;
@@ -2094,281 +1620,159 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
_set_error("Local constant must have a constant value as initializer.", lc->initializer);
return ERR_PARSE_ERROR;
}
- codegen.local_named_constants[lc->identifier->name] = codegen.get_constant_pos(lc->initializer->reduced_value);
+
+ codegen.add_local_constant(lc->identifier->name, lc->initializer->reduced_value);
} break;
case GDScriptParser::Node::PASS:
// Nothing to do.
break;
default: {
- //expression
+ // Expression.
if (s->is_expression()) {
- int ret2 = _parse_expression(codegen, static_cast<const GDScriptParser::ExpressionNode *>(s), p_stack_level, true);
- if (ret2 < 0) {
- return ERR_PARSE_ERROR;
+ GDScriptCodeGenerator::Address expr = _parse_expression(codegen, error, static_cast<const GDScriptParser::ExpressionNode *>(s), true);
+ if (error) {
+ return error;
+ }
+ if (expr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ codegen.generator->pop_temporary();
}
} else {
- ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Bug in bytecode compiler, unexpected node in parse tree while parsing statement."); //unreachable code
+ ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Bug in bytecode compiler, unexpected node in parse tree while parsing statement."); // Unreachable code.
}
} break;
}
}
- codegen.pop_stack_identifiers();
+ codegen.end_block();
return OK;
}
Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready) {
- Vector<int> bytecode;
+ Error error = OK;
CodeGen codegen;
+ codegen.generator = memnew(GDScriptByteCodeGenerator);
codegen.class_node = p_class;
codegen.script = p_script;
codegen.function_node = p_func;
- codegen.stack_max = 0;
- codegen.current_line = 0;
- codegen.call_max = 0;
- codegen.debug_stack = EngineDebugger::is_active();
- Vector<StringName> argnames;
- int stack_level = 0;
+ StringName func_name;
+ bool is_static = false;
+ MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
+ GDScriptDataType return_type;
+ return_type.has_type = true;
+ return_type.kind = GDScriptDataType::BUILTIN;
+ return_type.builtin_type = Variant::NIL;
+
+ if (p_func) {
+ func_name = p_func->identifier->name;
+ is_static = p_func->is_static;
+ rpc_mode = p_func->rpc_mode;
+ return_type = _gdtype_from_datatype(p_func->get_datatype());
+ } else {
+ if (p_for_ready) {
+ func_name = "_ready";
+ } else {
+ func_name = "@implicit_new";
+ }
+ }
+
+ codegen.function_name = func_name;
+ codegen.generator->write_start(p_script, func_name, is_static, rpc_mode, return_type);
+
int optional_parameters = 0;
if (p_func) {
for (int i = 0; i < p_func->parameters.size(); i++) {
- // since we are using properties now for most class access, allow shadowing of class members to make user's life easier.
- //
- //if (_is_class_member_property(p_script, p_func->arguments[i])) {
- // _set_error("Name for argument '" + String(p_func->arguments[i]) + "' can't shadow class property of the same name.", p_func);
- // return ERR_ALREADY_EXISTS;
- //}
-
- codegen.add_stack_identifier(p_func->parameters[i]->identifier->name, i);
-#ifdef TOOLS_ENABLED
- argnames.push_back(p_func->parameters[i]->identifier->name);
-#endif
+ const GDScriptParser::ParameterNode *parameter = p_func->parameters[i];
+ GDScriptDataType par_type = _gdtype_from_datatype(parameter->get_datatype());
+ uint32_t par_addr = codegen.generator->add_parameter(parameter->identifier->name, parameter->default_value != nullptr, par_type);
+ codegen.parameters[parameter->identifier->name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::FUNCTION_PARAMETER, par_addr, par_type);
+
if (p_func->parameters[i]->default_value != nullptr) {
optional_parameters++;
}
}
- stack_level = p_func->parameters.size();
}
- codegen.alloc_stack(stack_level);
-
- /* Parse initializer -if applies- */
-
+ // Parse initializer if applies.
bool is_implicit_initializer = !p_for_ready && !p_func;
bool is_initializer = p_func && String(p_func->identifier->name) == GDScriptLanguage::get_singleton()->strings._init;
+ bool is_for_ready = p_for_ready || (p_func && String(p_func->identifier->name) == "_ready");
- if (is_implicit_initializer) {
+ if (is_implicit_initializer || is_for_ready) {
// Initialize class fields.
for (int i = 0; i < p_class->members.size(); i++) {
if (p_class->members[i].type != GDScriptParser::ClassNode::Member::VARIABLE) {
continue;
}
const GDScriptParser::VariableNode *field = p_class->members[i].variable;
- if (field->onready) {
+ if (field->onready != is_for_ready) {
// Only initialize in _ready.
continue;
}
if (field->initializer) {
// Emit proper line change.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_LINE);
- codegen.opcodes.push_back(field->initializer->start_line);
+ codegen.generator->write_newline(field->initializer->start_line);
- int src_address = _parse_expression(codegen, field->initializer, stack_level, false, true);
- if (src_address < 0) {
- return ERR_PARSE_ERROR;
+ GDScriptCodeGenerator::Address src_address = _parse_expression(codegen, error, field->initializer, false, true);
+ if (error) {
+ memdelete(codegen.generator);
+ return error;
}
- int dst_address = codegen.script->member_indices[field->identifier->name].index;
- dst_address |= GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS;
+ GDScriptCodeGenerator::Address dst_address(GDScriptCodeGenerator::Address::MEMBER, codegen.script->member_indices[field->identifier->name].index, _gdtype_from_datatype(field->get_datatype()));
- if (!_generate_typed_assign(codegen, src_address, dst_address, _gdtype_from_datatype(field->get_datatype()), field->initializer->get_datatype())) {
- return ERR_PARSE_ERROR;
+ codegen.generator->write_assign(dst_address, src_address);
+ if (src_address.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ codegen.generator->pop_temporary();
}
}
}
}
- if (p_for_ready || (p_func && String(p_func->identifier->name) == "_ready")) {
- // Initialize class fields on ready.
- for (int i = 0; i < p_class->members.size(); i++) {
- if (p_class->members[i].type != GDScriptParser::ClassNode::Member::VARIABLE) {
- continue;
- }
- const GDScriptParser::VariableNode *field = p_class->members[i].variable;
- if (!field->onready) {
- continue;
- }
-
- if (field->initializer) {
- // Emit proper line change.
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_LINE);
- codegen.opcodes.push_back(field->initializer->start_line);
-
- int src_address = _parse_expression(codegen, field->initializer, stack_level, false, true);
- if (src_address < 0) {
- return ERR_PARSE_ERROR;
- }
- int dst_address = codegen.script->member_indices[field->identifier->name].index;
- dst_address |= GDScriptFunction::ADDR_TYPE_MEMBER << GDScriptFunction::ADDR_BITS;
-
- if (!_generate_typed_assign(codegen, src_address, dst_address, _gdtype_from_datatype(field->get_datatype()), field->initializer->get_datatype())) {
- return ERR_PARSE_ERROR;
- }
- }
- }
- }
-
- /* Parse default argument code -if applies- */
-
- Vector<int> defarg_addr;
- StringName func_name;
-
+ // Parse default argument code if applies.
if (p_func) {
if (optional_parameters > 0) {
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_JUMP_TO_DEF_ARGUMENT);
- defarg_addr.push_back(codegen.opcodes.size());
+ codegen.generator->start_parameters();
for (int i = p_func->parameters.size() - optional_parameters; i < p_func->parameters.size(); i++) {
- int src_addr = _parse_expression(codegen, p_func->parameters[i]->default_value, stack_level, true);
- if (src_addr < 0) {
- return ERR_PARSE_ERROR;
+ const GDScriptParser::ParameterNode *parameter = p_func->parameters[i];
+ GDScriptCodeGenerator::Address src_addr = _parse_expression(codegen, error, parameter->default_value, true);
+ if (error) {
+ memdelete(codegen.generator);
+ return error;
}
- int dst_addr = codegen.stack_identifiers[p_func->parameters[i]->identifier->name] | (GDScriptFunction::ADDR_TYPE_STACK_VARIABLE << GDScriptFunction::ADDR_BITS);
- if (!_generate_typed_assign(codegen, src_addr, dst_addr, _gdtype_from_datatype(p_func->parameters[i]->get_datatype()), p_func->parameters[i]->default_value->get_datatype())) {
- return ERR_PARSE_ERROR;
+ GDScriptCodeGenerator::Address dst_addr = codegen.parameters[parameter->identifier->name];
+ codegen.generator->write_assign(dst_addr, src_addr);
+ if (src_addr.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ codegen.generator->pop_temporary();
}
- defarg_addr.push_back(codegen.opcodes.size());
}
- defarg_addr.invert();
+ codegen.generator->end_parameters();
}
- func_name = p_func->identifier->name;
- codegen.function_name = func_name;
- Error err = _parse_block(codegen, p_func->body, stack_level);
+ Error err = _parse_block(codegen, p_func->body);
if (err) {
+ memdelete(codegen.generator);
return err;
}
-
- } else {
- if (p_for_ready) {
- func_name = "_ready";
- } else {
- func_name = "@implicit_new";
- }
- }
-
- codegen.function_name = func_name;
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_END);
-
- /*
- if (String(p_func->name)=="") { //initializer func
- gdfunc = &p_script->initializer;
- */
- //} else { //regular func
- p_script->member_functions[func_name] = memnew(GDScriptFunction);
- GDScriptFunction *gdfunc = p_script->member_functions[func_name];
- //}
-
- if (p_func) {
- gdfunc->_static = p_func->is_static;
- gdfunc->rpc_mode = p_func->rpc_mode;
- gdfunc->argument_types.resize(p_func->parameters.size());
- for (int i = 0; i < p_func->parameters.size(); i++) {
- gdfunc->argument_types.write[i] = _gdtype_from_datatype(p_func->parameters[i]->get_datatype());
- }
- gdfunc->return_type = _gdtype_from_datatype(p_func->get_datatype());
- } else {
- gdfunc->_static = false;
- gdfunc->rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
- gdfunc->return_type = GDScriptDataType();
- gdfunc->return_type.has_type = true;
- gdfunc->return_type.kind = GDScriptDataType::BUILTIN;
- gdfunc->return_type.builtin_type = Variant::NIL;
- }
-
-#ifdef TOOLS_ENABLED
- gdfunc->arg_names = argnames;
-#endif
- //constants
- if (codegen.constant_map.size()) {
- gdfunc->_constant_count = codegen.constant_map.size();
- gdfunc->constants.resize(codegen.constant_map.size());
- gdfunc->_constants_ptr = gdfunc->constants.ptrw();
- const Variant *K = nullptr;
- while ((K = codegen.constant_map.next(K))) {
- int idx = codegen.constant_map[*K];
- gdfunc->constants.write[idx] = *K;
- }
- } else {
- gdfunc->_constants_ptr = nullptr;
- gdfunc->_constant_count = 0;
- }
- //global names
- if (codegen.name_map.size()) {
- gdfunc->global_names.resize(codegen.name_map.size());
- gdfunc->_global_names_ptr = &gdfunc->global_names[0];
- for (Map<StringName, int>::Element *E = codegen.name_map.front(); E; E = E->next()) {
- gdfunc->global_names.write[E->get()] = E->key();
- }
- gdfunc->_global_names_count = gdfunc->global_names.size();
-
- } else {
- gdfunc->_global_names_ptr = nullptr;
- gdfunc->_global_names_count = 0;
}
-#ifdef TOOLS_ENABLED
- // Named globals
- if (codegen.named_globals.size()) {
- gdfunc->named_globals.resize(codegen.named_globals.size());
- gdfunc->_named_globals_ptr = gdfunc->named_globals.ptr();
- for (int i = 0; i < codegen.named_globals.size(); i++) {
- gdfunc->named_globals.write[i] = codegen.named_globals[i];
- }
- gdfunc->_named_globals_count = gdfunc->named_globals.size();
- }
-#endif
-
- if (codegen.opcodes.size()) {
- gdfunc->code = codegen.opcodes;
- gdfunc->_code_ptr = &gdfunc->code[0];
- gdfunc->_code_size = codegen.opcodes.size();
-
- } else {
- gdfunc->_code_ptr = nullptr;
- gdfunc->_code_size = 0;
- }
-
- if (defarg_addr.size()) {
- gdfunc->default_arguments = defarg_addr;
- gdfunc->_default_arg_count = defarg_addr.size() - 1;
- gdfunc->_default_arg_ptr = &gdfunc->default_arguments[0];
- } else {
- gdfunc->_default_arg_count = 0;
- gdfunc->_default_arg_ptr = nullptr;
- }
-
- gdfunc->_argument_count = p_func ? p_func->parameters.size() : 0;
- gdfunc->_stack_size = codegen.stack_max;
- gdfunc->_call_size = codegen.call_max;
- gdfunc->name = func_name;
#ifdef DEBUG_ENABLED
if (EngineDebugger::is_active()) {
String signature;
- //path
+ // Path.
if (p_script->get_path() != String()) {
signature += p_script->get_path();
}
- //loc
+ // Location.
if (p_func) {
signature += "::" + itos(p_func->body->start_line);
} else {
signature += "::0";
}
- //function and class
+ // Function and class.
if (p_class->identifier) {
signature += "::" + String(p_class->identifier->name) + "." + String(func_name);
@@ -2376,65 +1780,41 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
signature += "::" + String(func_name);
}
- gdfunc->profile.signature = signature;
+ codegen.generator->set_signature(signature);
}
#endif
- gdfunc->_script = p_script;
- gdfunc->source = source;
-#ifdef DEBUG_ENABLED
-
- {
- gdfunc->func_cname = (String(source) + " - " + String(func_name)).utf8();
- gdfunc->_func_cname = gdfunc->func_cname.get_data();
- }
-
-#endif
if (p_func) {
- gdfunc->_initial_line = p_func->start_line;
+ codegen.generator->set_initial_line(p_func->start_line);
#ifdef TOOLS_ENABLED
-
p_script->member_lines[func_name] = p_func->start_line;
#endif
} else {
- gdfunc->_initial_line = 0;
+ codegen.generator->set_initial_line(0);
}
- if (codegen.debug_stack) {
- gdfunc->stack_debug = codegen.stack_debug;
- }
+ GDScriptFunction *gd_function = codegen.generator->write_end();
if (is_initializer) {
- p_script->initializer = gdfunc;
- }
- if (is_implicit_initializer) {
- p_script->implicit_initializer = gdfunc;
+ p_script->initializer = gd_function;
+ } else if (is_implicit_initializer) {
+ p_script->implicit_initializer = gd_function;
}
+ p_script->member_functions[func_name] = gd_function;
+
+ memdelete(codegen.generator);
+
return OK;
}
Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::VariableNode *p_variable, bool p_is_setter) {
- Vector<int> bytecode;
+ Error error = OK;
CodeGen codegen;
+ codegen.generator = memnew(GDScriptByteCodeGenerator);
codegen.class_node = p_class;
codegen.script = p_script;
- codegen.function_node = nullptr;
- codegen.stack_max = 0;
- codegen.current_line = 0;
- codegen.call_max = 0;
- codegen.debug_stack = EngineDebugger::is_active();
- Vector<StringName> argnames;
-
- int stack_level = 0;
-
- if (p_is_setter) {
- codegen.add_stack_identifier(p_variable->setter_parameter->name, stack_level++);
- argnames.push_back(p_variable->setter_parameter->name);
- }
-
- codegen.alloc_stack(stack_level);
StringName func_name;
@@ -2443,76 +1823,33 @@ Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptP
} else {
func_name = "@" + p_variable->identifier->name + "_getter";
}
- codegen.function_name = func_name;
- Error err = _parse_block(codegen, p_is_setter ? p_variable->setter : p_variable->getter, stack_level);
- if (err != OK) {
- return err;
+ GDScriptDataType return_type;
+ if (p_is_setter) {
+ return_type.has_type = true;
+ return_type.kind = GDScriptDataType::BUILTIN;
+ return_type.builtin_type = Variant::NIL;
+ } else {
+ return_type = _gdtype_from_datatype(p_variable->get_datatype());
}
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_END);
+ codegen.generator->write_start(p_script, func_name, false, p_variable->rpc_mode, return_type);
- p_script->member_functions[func_name] = memnew(GDScriptFunction);
- GDScriptFunction *gdfunc = p_script->member_functions[func_name];
-
- gdfunc->_static = false;
- gdfunc->rpc_mode = p_variable->rpc_mode;
- gdfunc->argument_types.resize(p_is_setter ? 1 : 0);
- gdfunc->return_type = _gdtype_from_datatype(p_variable->get_datatype());
-#ifdef TOOLS_ENABLED
- gdfunc->arg_names = argnames;
-#endif
-
- // TODO: Unify this with function compiler.
- //constants
- if (codegen.constant_map.size()) {
- gdfunc->_constant_count = codegen.constant_map.size();
- gdfunc->constants.resize(codegen.constant_map.size());
- gdfunc->_constants_ptr = gdfunc->constants.ptrw();
- const Variant *K = nullptr;
- while ((K = codegen.constant_map.next(K))) {
- int idx = codegen.constant_map[*K];
- gdfunc->constants.write[idx] = *K;
- }
- } else {
- gdfunc->_constants_ptr = nullptr;
- gdfunc->_constant_count = 0;
+ if (p_is_setter) {
+ uint32_t par_addr = codegen.generator->add_parameter(p_variable->setter_parameter->name, false, _gdtype_from_datatype(p_variable->get_datatype()));
+ codegen.parameters[p_variable->setter_parameter->name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::FUNCTION_PARAMETER, par_addr, _gdtype_from_datatype(p_variable->get_datatype()));
}
- //global names
- if (codegen.name_map.size()) {
- gdfunc->global_names.resize(codegen.name_map.size());
- gdfunc->_global_names_ptr = &gdfunc->global_names[0];
- for (Map<StringName, int>::Element *E = codegen.name_map.front(); E; E = E->next()) {
- gdfunc->global_names.write[E->get()] = E->key();
- }
- gdfunc->_global_names_count = gdfunc->global_names.size();
- } else {
- gdfunc->_global_names_ptr = nullptr;
- gdfunc->_global_names_count = 0;
+ error = _parse_block(codegen, p_is_setter ? p_variable->setter : p_variable->getter);
+ if (error) {
+ memdelete(codegen.generator);
+ return error;
}
-#ifdef TOOLS_ENABLED
- // Named globals
- if (codegen.named_globals.size()) {
- gdfunc->named_globals.resize(codegen.named_globals.size());
- gdfunc->_named_globals_ptr = gdfunc->named_globals.ptr();
- for (int i = 0; i < codegen.named_globals.size(); i++) {
- gdfunc->named_globals.write[i] = codegen.named_globals[i];
- }
- gdfunc->_named_globals_count = gdfunc->named_globals.size();
- }
-#endif
+ GDScriptFunction *gd_function = codegen.generator->write_end();
+
+ p_script->member_functions[func_name] = gd_function;
- gdfunc->code = codegen.opcodes;
- gdfunc->_code_ptr = &gdfunc->code[0];
- gdfunc->_code_size = codegen.opcodes.size();
- gdfunc->_default_arg_count = 0;
- gdfunc->_default_arg_ptr = nullptr;
- gdfunc->_argument_count = argnames.size();
- gdfunc->_stack_size = codegen.stack_max;
- gdfunc->_call_size = codegen.call_max;
- gdfunc->name = func_name;
#ifdef DEBUG_ENABLED
if (EngineDebugger::is_active()) {
String signature;
@@ -2531,29 +1868,15 @@ Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptP
signature += "::" + String(func_name);
}
- gdfunc->profile.signature = signature;
+ codegen.generator->set_signature(signature);
}
#endif
- gdfunc->_script = p_script;
- gdfunc->source = source;
+ codegen.generator->set_initial_line(p_is_setter ? p_variable->setter->start_line : p_variable->getter->start_line);
-#ifdef DEBUG_ENABLED
-
- {
- gdfunc->func_cname = (String(source) + " - " + String(func_name)).utf8();
- gdfunc->_func_cname = gdfunc->func_cname.get_data();
- }
-
-#endif
- gdfunc->_initial_line = p_is_setter ? p_variable->setter->start_line : p_variable->getter->start_line;
#ifdef TOOLS_ENABLED
-
- p_script->member_lines[func_name] = gdfunc->_initial_line;
+ p_script->member_lines[func_name] = p_is_setter ? p_variable->setter->start_line : p_variable->getter->start_line;
#endif
-
- if (codegen.debug_stack) {
- gdfunc->stack_debug = codegen.stack_debug;
- }
+ memdelete(codegen.generator);
return OK;
}
@@ -2609,16 +1932,27 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
p_script->_base = base.ptr();
if (p_class->base_type.kind == GDScriptParser::DataType::CLASS && p_class->base_type.class_type != nullptr) {
- if (!parsed_classes.has(p_script->_base)) {
- if (parsing_classes.has(p_script->_base)) {
- String class_name = p_class->identifier ? p_class->identifier->name : "<main>";
- _set_error("Cyclic class reference for '" + class_name + "'.", p_class);
- return ERR_PARSE_ERROR;
+ if (p_class->base_type.script_path == main_script->path) {
+ if (!parsed_classes.has(p_script->_base)) {
+ if (parsing_classes.has(p_script->_base)) {
+ String class_name = p_class->identifier ? p_class->identifier->name : "<main>";
+ _set_error("Cyclic class reference for '" + class_name + "'.", p_class);
+ return ERR_PARSE_ERROR;
+ }
+ Error err = _parse_class_level(p_script->_base, p_class->base_type.class_type, p_keep_state);
+ if (err) {
+ return err;
+ }
}
- Error err = _parse_class_level(p_script->_base, p_class->base_type.class_type, p_keep_state);
+ } else {
+ Error err = OK;
+ base = GDScriptCache::get_full_script(p_class->base_type.script_path, err, main_script->path);
if (err) {
return err;
}
+ if (base.is_null() && !base->is_valid()) {
+ return ERR_COMPILATION_FAILED;
+ }
}
}
@@ -2696,11 +2030,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
const GDScriptParser::ConstantNode *constant = member.constant;
StringName name = constant->identifier->name;
- ERR_CONTINUE(constant->initializer->type != GDScriptParser::Node::LITERAL);
-
- const GDScriptParser::LiteralNode *literal = static_cast<const GDScriptParser::LiteralNode *>(constant->initializer);
-
- p_script->constants.insert(name, literal->value);
+ p_script->constants.insert(name, constant->initializer->reduced_value);
#ifdef TOOLS_ENABLED
p_script->member_lines[name] = constant->start_line;
diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h
index e8601f69c7..80fba6a934 100644
--- a/modules/gdscript/gdscript_compiler.h
+++ b/modules/gdscript/gdscript_compiler.h
@@ -33,109 +33,88 @@
#include "core/set.h"
#include "gdscript.h"
+#include "gdscript_codegen.h"
#include "gdscript_function.h"
#include "gdscript_parser.h"
class GDScriptCompiler {
- const GDScriptParser *parser;
+ const GDScriptParser *parser = nullptr;
Set<GDScript *> parsed_classes;
Set<GDScript *> parsing_classes;
- GDScript *main_script;
+ GDScript *main_script = nullptr;
+
struct CodeGen {
- GDScript *script;
- const GDScriptParser::ClassNode *class_node;
- const GDScriptParser::FunctionNode *function_node;
+ GDScript *script = nullptr;
+ const GDScriptParser::ClassNode *class_node = nullptr;
+ const GDScriptParser::FunctionNode *function_node = nullptr;
StringName function_name;
- bool debug_stack;
-
- List<Map<StringName, int>> stack_id_stack;
- Map<StringName, int> stack_identifiers;
-
- List<GDScriptFunction::StackDebug> stack_debug;
- List<Map<StringName, int>> block_identifier_stack;
- Map<StringName, int> block_identifiers;
- Map<StringName, int> local_named_constants;
-
- void add_stack_identifier(const StringName &p_id, int p_stackpos) {
- stack_identifiers[p_id] = p_stackpos;
- if (debug_stack) {
- block_identifiers[p_id] = p_stackpos;
- GDScriptFunction::StackDebug sd;
- sd.added = true;
- sd.line = current_line;
- sd.identifier = p_id;
- sd.pos = p_stackpos;
- stack_debug.push_back(sd);
- }
+ GDScriptCodeGenerator *generator = nullptr;
+ Map<StringName, GDScriptCodeGenerator::Address> parameters;
+ Map<StringName, GDScriptCodeGenerator::Address> locals;
+ List<Set<StringName>> locals_in_scope;
+
+ GDScriptCodeGenerator::Address add_local(const StringName &p_name, const GDScriptDataType &p_type) {
+ uint32_t addr = generator->add_local(p_name, p_type);
+ locals[p_name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::LOCAL_VARIABLE, addr, p_type);
+ locals_in_scope.back()->get().insert(p_name);
+ return locals[p_name];
}
- void push_stack_identifiers() {
- stack_id_stack.push_back(stack_identifiers);
- if (debug_stack) {
- block_identifier_stack.push_back(block_identifiers);
- block_identifiers.clear();
- }
+ GDScriptCodeGenerator::Address add_local_constant(const StringName &p_name, const Variant &p_value) {
+ uint32_t addr = generator->add_local_constant(p_name, p_value);
+ locals[p_name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::LOCAL_CONSTANT, addr);
+ return locals[p_name];
}
- void pop_stack_identifiers() {
- stack_identifiers = stack_id_stack.back()->get();
- stack_id_stack.pop_back();
-
- if (debug_stack) {
- for (Map<StringName, int>::Element *E = block_identifiers.front(); E; E = E->next()) {
- GDScriptFunction::StackDebug sd;
- sd.added = false;
- sd.identifier = E->key();
- sd.line = current_line;
- sd.pos = E->get();
- stack_debug.push_back(sd);
- }
- block_identifiers = block_identifier_stack.back()->get();
- block_identifier_stack.pop_back();
- }
+ GDScriptCodeGenerator::Address add_temporary(const GDScriptDataType &p_type = GDScriptDataType()) {
+ uint32_t addr = generator->add_temporary();
+ return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::TEMPORARY, addr, p_type);
}
- HashMap<Variant, int, VariantHasher, VariantComparator> constant_map;
- Map<StringName, int> name_map;
-#ifdef TOOLS_ENABLED
- Vector<StringName> named_globals;
-#endif
-
- int get_name_map_pos(const StringName &p_identifier) {
- int ret;
- if (!name_map.has(p_identifier)) {
- ret = name_map.size();
- name_map[p_identifier] = ret;
- } else {
- ret = name_map[p_identifier];
+ GDScriptCodeGenerator::Address add_constant(const Variant &p_constant) {
+ GDScriptDataType type;
+ type.has_type = true;
+ type.kind = GDScriptDataType::BUILTIN;
+ type.builtin_type = p_constant.get_type();
+ if (type.builtin_type == Variant::OBJECT) {
+ Object *obj = p_constant;
+ if (obj) {
+ type.kind = GDScriptDataType::NATIVE;
+ type.native_type = obj->get_class_name();
+
+ Ref<Script> script = obj->get_script();
+ if (script.is_valid()) {
+ type.script_type = script;
+ Ref<GDScript> gdscript = script;
+ if (gdscript.is_valid()) {
+ type.kind = GDScriptDataType::GDSCRIPT;
+ } else {
+ type.kind = GDScriptDataType::SCRIPT;
+ }
+ }
+ } else {
+ type.builtin_type = Variant::NIL;
+ }
}
- return ret;
- }
- int get_constant_pos(const Variant &p_constant) {
- if (constant_map.has(p_constant)) {
- return constant_map[p_constant] | (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
- }
- int pos = constant_map.size();
- constant_map[p_constant] = pos;
- return pos | (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
+ uint32_t addr = generator->add_or_get_constant(p_constant);
+ return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::CONSTANT, addr, type);
}
- Vector<int> opcodes;
- void alloc_stack(int p_level) {
- if (p_level >= stack_max) {
- stack_max = p_level + 1;
- }
+ void start_block() {
+ Set<StringName> scope;
+ locals_in_scope.push_back(scope);
+ generator->start_block();
}
- void alloc_call(int p_params) {
- if (p_params >= call_max) {
- call_max = p_params;
+
+ void end_block() {
+ Set<StringName> &scope = locals_in_scope.back()->get();
+ for (Set<StringName>::Element *E = scope.front(); E; E = E->next()) {
+ locals.erase(E->get());
}
+ locals_in_scope.pop_back();
+ generator->end_block();
}
-
- int current_line;
- int stack_max;
- int call_max;
};
bool _is_class_member_property(CodeGen &codegen, const StringName &p_name);
@@ -143,17 +122,16 @@ class GDScriptCompiler {
void _set_error(const String &p_error, const GDScriptParser::Node *p_node);
- bool _create_unary_operator(CodeGen &codegen, const GDScriptParser::UnaryOpNode *on, Variant::Operator op, int p_stack_level);
- bool _create_binary_operator(CodeGen &codegen, const GDScriptParser::BinaryOpNode *on, Variant::Operator op, int p_stack_level, bool p_initializer = false, int p_index_addr = 0);
- bool _create_binary_operator(CodeGen &codegen, const GDScriptParser::ExpressionNode *p_left_operand, const GDScriptParser::ExpressionNode *p_right_operand, Variant::Operator op, int p_stack_level, bool p_initializer = false, int p_index_addr = 0);
- bool _generate_typed_assign(CodeGen &codegen, int p_src_address, int p_dst_address, const GDScriptDataType &p_datatype, const GDScriptParser::DataType &p_value_type);
+ Error _create_binary_operator(CodeGen &codegen, const GDScriptParser::BinaryOpNode *on, Variant::Operator op, bool p_initializer = false, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address());
+ Error _create_binary_operator(CodeGen &codegen, const GDScriptParser::ExpressionNode *p_left_operand, const GDScriptParser::ExpressionNode *p_right_operand, Variant::Operator op, bool p_initializer = false, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address());
GDScriptDataType _gdtype_from_datatype(const GDScriptParser::DataType &p_datatype) const;
- int _parse_assign_right_expression(CodeGen &codegen, const GDScriptParser::AssignmentNode *p_assignment, int p_stack_level, int p_index_addr = 0);
- int _parse_expression(CodeGen &codegen, const GDScriptParser::ExpressionNode *p_expression, int p_stack_level, bool p_root = false, bool p_initializer = false, int p_index_addr = 0);
- Error _parse_match_pattern(CodeGen &codegen, const GDScriptParser::PatternNode *p_pattern, int p_stack_level, int p_value_addr, int p_type_addr, int &r_bound_variables, Vector<int> &r_patch_addresses, Vector<int> &r_block_patch_address);
- Error _parse_block(CodeGen &codegen, const GDScriptParser::SuiteNode *p_block, int p_stack_level = 0, int p_break_addr = -1, int p_continue_addr = -1);
+ GDScriptCodeGenerator::Address _parse_assign_right_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::AssignmentNode *p_assignmentint, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address());
+ GDScriptCodeGenerator::Address _parse_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::ExpressionNode *p_expression, bool p_root = false, bool p_initializer = false, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address());
+ GDScriptCodeGenerator::Address _parse_match_pattern(CodeGen &codegen, Error &r_error, const GDScriptParser::PatternNode *p_pattern, const GDScriptCodeGenerator::Address &p_value_addr, const GDScriptCodeGenerator::Address &p_type_addr, const GDScriptCodeGenerator::Address &p_previous_test, bool p_is_first, bool p_is_nested);
+ void _add_locals_in_block(CodeGen &codegen, const GDScriptParser::SuiteNode *p_block);
+ Error _parse_block(CodeGen &codegen, const GDScriptParser::SuiteNode *p_block, bool p_add_locals = true);
Error _parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false);
Error _parse_setter_getter(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::VariableNode *p_variable, bool p_is_setter);
Error _parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 88bf8cde0f..2e372575da 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -483,6 +483,8 @@ String GDScriptLanguage::make_function(const String &p_class, const String &p_na
#ifdef TOOLS_ENABLED
+#define COMPLETION_RECURSION_LIMIT 200
+
struct GDScriptCompletionIdentifier {
GDScriptParser::DataType type;
String enumeration;
@@ -766,9 +768,11 @@ static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite,
}
}
-static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result);
+static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth);
+
+static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, bool p_only_functions, bool p_static, bool p_parent_only, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth) {
+ ERR_FAIL_COND(p_recursion_depth > COMPLETION_RECURSION_LIMIT);
-static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, bool p_only_functions, bool p_static, bool p_parent_only, Map<String, ScriptCodeCompletionOption> &r_result) {
if (!p_parent_only) {
bool outer = false;
const GDScriptParser::ClassNode *clss = p_class;
@@ -820,7 +824,6 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
break;
case GDScriptParser::ClassNode::Member::SIGNAL:
if (p_only_functions || outer) {
- clss = clss->outer;
continue;
}
option = ScriptCodeCompletionOption(member.signal->identifier->name, ScriptCodeCompletionOption::KIND_SIGNAL);
@@ -840,10 +843,12 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
base_type.type = p_class->base_type;
base_type.type.is_meta_type = p_static;
- _find_identifiers_in_base(base_type, p_only_functions, r_result);
+ _find_identifiers_in_base(base_type, p_only_functions, r_result, p_recursion_depth + 1);
}
-static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result) {
+static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth) {
+ ERR_FAIL_COND(p_recursion_depth > COMPLETION_RECURSION_LIMIT);
+
GDScriptParser::DataType base_type = p_base.type;
bool _static = base_type.is_meta_type;
@@ -856,7 +861,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
while (!base_type.has_no_type()) {
switch (base_type.kind) {
case GDScriptParser::DataType::CLASS: {
- _find_identifiers_in_class(base_type.class_type, p_only_functions, _static, false, r_result);
+ _find_identifiers_in_class(base_type.class_type, p_only_functions, _static, false, r_result, p_recursion_depth + 1);
// This already finds all parent identifiers, so we are done.
base_type = GDScriptParser::DataType();
} break;
@@ -1007,14 +1012,14 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
}
}
-static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result) {
+static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool p_only_functions, Map<String, ScriptCodeCompletionOption> &r_result, int p_recursion_depth) {
if (!p_only_functions && p_context.current_suite) {
// This includes function parameters, since they are also locals.
_find_identifiers_in_suite(p_context.current_suite, r_result);
}
if (p_context.current_class) {
- _find_identifiers_in_class(p_context.current_class, p_only_functions, (!p_context.current_function || p_context.current_function->is_static), false, r_result);
+ _find_identifiers_in_class(p_context.current_class, p_only_functions, (!p_context.current_function || p_context.current_function->is_static), false, r_result, p_recursion_depth + 1);
}
for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) {
@@ -2453,7 +2458,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
break;
}
if (!_guess_expression_type(completion_context, static_cast<const GDScriptParser::AssignmentNode *>(completion_context.node)->assignee, type)) {
- _find_identifiers(completion_context, false, options);
+ _find_identifiers(completion_context, false, options, 0);
r_forced = true;
break;
}
@@ -2462,7 +2467,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
_find_enumeration_candidates(completion_context, type.enumeration, options);
r_forced = options.size() > 0;
} else {
- _find_identifiers(completion_context, false, options);
+ _find_identifiers(completion_context, false, options, 0);
r_forced = true;
}
} break;
@@ -2470,7 +2475,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
is_function = true;
[[fallthrough]];
case GDScriptParser::COMPLETION_IDENTIFIER: {
- _find_identifiers(completion_context, is_function, options);
+ _find_identifiers(completion_context, is_function, options, 0);
} break;
case GDScriptParser::COMPLETION_ATTRIBUTE_METHOD:
is_function = true;
@@ -2484,7 +2489,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
break;
}
- _find_identifiers_in_base(base, is_function, options);
+ _find_identifiers_in_base(base, is_function, options, 0);
}
} break;
case GDScriptParser::COMPLETION_SUBSCRIPT: {
@@ -2504,7 +2509,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
c.current_class = nullptr;
}
- _find_identifiers_in_base(base, false, options);
+ _find_identifiers_in_base(base, false, options, 0);
} break;
case GDScriptParser::COMPLETION_TYPE_ATTRIBUTE: {
if (!completion_context.current_class) {
@@ -2530,7 +2535,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
// TODO: Improve this to only list types.
if (found) {
- _find_identifiers_in_base(base, false, options);
+ _find_identifiers_in_base(base, false, options, 0);
}
r_forced = true;
} break;
@@ -2651,7 +2656,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path
if (!completion_context.current_class) {
break;
}
- _find_identifiers_in_class(completion_context.current_class, true, false, true, options);
+ _find_identifiers_in_class(completion_context.current_class, true, false, true, options, 0);
} break;
}
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index a4e37a79f8..e59f99fc56 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -34,6 +34,10 @@
#include "gdscript.h"
#include "gdscript_functions.h"
+#ifdef DEBUG_ENABLED
+#include "core/string_builder.h"
+#endif
+
Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_instance, GDScript *p_script, Variant &self, Variant &static_ref, Variant *p_stack, String &r_error) const {
int address = p_address & ADDR_MASK;
@@ -105,9 +109,9 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta
#ifdef TOOLS_ENABLED
case ADDR_TYPE_NAMED_GLOBAL: {
#ifdef DEBUG_ENABLED
- ERR_FAIL_INDEX_V(address, _named_globals_count, nullptr);
+ ERR_FAIL_INDEX_V(address, _global_names_count, nullptr);
#endif
- StringName id = _named_globals_ptr[address];
+ StringName id = _global_names_ptr[address];
if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(id)) {
return (Variant *)&GDScriptLanguage::get_singleton()->get_named_globals_map()[id];
@@ -212,7 +216,6 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
&&OPCODE_CALL_RETURN, \
&&OPCODE_CALL_ASYNC, \
&&OPCODE_CALL_BUILT_IN, \
- &&OPCODE_CALL_SELF, \
&&OPCODE_CALL_SELF_BASE, \
&&OPCODE_AWAIT, \
&&OPCODE_AWAIT_RESUME, \
@@ -1055,7 +1058,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
err_text = "Got a freed object as a result of the call.";
OPCODE_BREAK;
}
- if (obj->is_class_ptr(GDScriptFunctionState::get_class_ptr_static())) {
+ if (obj && obj->is_class_ptr(GDScriptFunctionState::get_class_ptr_static())) {
err_text = R"(Trying to call an async function without "await".)";
OPCODE_BREAK;
}
@@ -1139,10 +1142,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
- OPCODE(OPCODE_CALL_SELF) {
- OPCODE_BREAK;
- }
-
OPCODE(OPCODE_CALL_SELF_BASE) {
CHECK_SPACE(2);
int self_fun = _code_ptr[ip + 1];
@@ -1214,8 +1213,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
DISPATCH_OPCODE;
OPCODE(OPCODE_AWAIT) {
- int ipofs = 2;
- CHECK_SPACE(3);
+ CHECK_SPACE(2);
//do the oneshot connect
GET_VARIANT_PTR(argobj, 1);
@@ -1265,7 +1263,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
gdfs->state.stack_size = _stack_size;
gdfs->state.self = self;
gdfs->state.alloca_size = alloca_size;
- gdfs->state.ip = ip + ipofs;
+ gdfs->state.ip = ip + 2;
gdfs->state.line = line;
gdfs->state.script = _script;
{
@@ -1884,3 +1882,506 @@ GDScriptFunctionState::~GDScriptFunctionState() {
instances_list.remove_from_list();
}
}
+
+#ifdef DEBUG_ENABLED
+static String _get_variant_string(const Variant &p_variant) {
+ String txt;
+ if (p_variant.get_type() == Variant::STRING) {
+ txt = "\"" + String(p_variant) + "\"";
+ } else if (p_variant.get_type() == Variant::STRING_NAME) {
+ txt = "&\"" + String(p_variant) + "\"";
+ } else if (p_variant.get_type() == Variant::NODE_PATH) {
+ txt = "^\"" + String(p_variant) + "\"";
+ } else if (p_variant.get_type() == Variant::OBJECT) {
+ Object *obj = p_variant;
+ if (!obj) {
+ txt = "null";
+ } else {
+ GDScriptNativeClass *cls = Object::cast_to<GDScriptNativeClass>(obj);
+ if (cls) {
+ txt += cls->get_name();
+ txt += " (class)";
+ } else {
+ txt = obj->get_class();
+ if (obj->get_script_instance()) {
+ txt += "(" + obj->get_script_instance()->get_script()->get_path() + ")";
+ }
+ }
+ }
+ } else {
+ txt = p_variant;
+ }
+ return txt;
+}
+
+static String _disassemble_address(const GDScript *p_script, const GDScriptFunction &p_function, int p_address) {
+ int addr = p_address & GDScriptFunction::ADDR_MASK;
+
+ switch (p_address >> GDScriptFunction::ADDR_BITS) {
+ case GDScriptFunction::ADDR_TYPE_SELF: {
+ return "self";
+ } break;
+ case GDScriptFunction::ADDR_TYPE_CLASS: {
+ return "class";
+ } break;
+ case GDScriptFunction::ADDR_TYPE_MEMBER: {
+ return "member(" + p_script->debug_get_member_by_index(addr) + ")";
+ } break;
+ case GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT: {
+ return "class_const(" + p_function.get_global_name(addr) + ")";
+ } break;
+ case GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT: {
+ return "const(" + _get_variant_string(p_function.get_constant(addr)) + ")";
+ } break;
+ case GDScriptFunction::ADDR_TYPE_STACK: {
+ return "stack(" + itos(addr) + ")";
+ } break;
+ case GDScriptFunction::ADDR_TYPE_STACK_VARIABLE: {
+ return "var_stack(" + itos(addr) + ")";
+ } break;
+ case GDScriptFunction::ADDR_TYPE_GLOBAL: {
+ return "global(" + _get_variant_string(GDScriptLanguage::get_singleton()->get_global_array()[addr]) + ")";
+ } break;
+ case GDScriptFunction::ADDR_TYPE_NAMED_GLOBAL: {
+ return "named_global(" + p_function.get_global_name(addr) + ")";
+ } break;
+ case GDScriptFunction::ADDR_TYPE_NIL: {
+ return "nil";
+ } break;
+ }
+
+ return "<err>";
+}
+
+void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
+#define DADDR(m_ip) (_disassemble_address(_script, *this, _code_ptr[ip + m_ip]))
+
+ for (int ip = 0; ip < _code_size;) {
+ StringBuilder text;
+ int incr = 0;
+
+ text += " ";
+ text += itos(ip);
+ text += ": ";
+
+ // This makes the compiler complain if some opcode is unchecked in the switch.
+ Opcode code = Opcode(_code_ptr[ip]);
+
+ switch (code) {
+ case OPCODE_OPERATOR: {
+ int operation = _code_ptr[ip + 1];
+
+ text += "operator ";
+
+ text += DADDR(4);
+ text += " = ";
+ text += DADDR(2);
+ text += " ";
+ text += Variant::get_operator_name(Variant::Operator(operation));
+ text += " ";
+ text += DADDR(3);
+
+ incr += 5;
+ } break;
+ case OPCODE_EXTENDS_TEST: {
+ text += "is object ";
+ text += DADDR(3);
+ text += " = ";
+ text += DADDR(1);
+ text += " is ";
+ text += DADDR(2);
+
+ incr += 4;
+ } break;
+ case OPCODE_IS_BUILTIN: {
+ text += "is builtin ";
+ text += DADDR(3);
+ text += " = ";
+ text += DADDR(1);
+ text += " is ";
+ text += Variant::get_type_name(Variant::Type(_code_ptr[ip + 2]));
+
+ incr += 4;
+ } break;
+ case OPCODE_SET: {
+ text += "set ";
+ text += DADDR(1);
+ text += "[";
+ text += DADDR(2);
+ text += "] = ";
+ text += DADDR(3);
+
+ incr += 4;
+ } break;
+ case OPCODE_GET: {
+ text += "get ";
+ text += DADDR(3);
+ text += " = ";
+ text += DADDR(1);
+ text += "[";
+ text += DADDR(2);
+ text += "]";
+
+ incr += 4;
+ } break;
+ case OPCODE_SET_NAMED: {
+ text += "set_named ";
+ text += DADDR(1);
+ text += "[\"";
+ text += _global_names_ptr[_code_ptr[ip + 2]];
+ text += "\"] = ";
+ text += DADDR(3);
+
+ incr += 4;
+ } break;
+ case OPCODE_GET_NAMED: {
+ text += "get_named ";
+ text += DADDR(3);
+ text += " = ";
+ text += DADDR(1);
+ text += "[\"";
+ text += _global_names_ptr[_code_ptr[ip + 2]];
+ text += "\"]";
+
+ incr += 4;
+ } break;
+ case OPCODE_SET_MEMBER: {
+ text += "set_member ";
+ text += "[\"";
+ text += _global_names_ptr[_code_ptr[ip + 1]];
+ text += "\"] = ";
+ text += DADDR(2);
+
+ incr += 3;
+ } break;
+ case OPCODE_GET_MEMBER: {
+ text += "get_member ";
+ text += DADDR(2);
+ text += " = ";
+ text += "[\"";
+ text += _global_names_ptr[_code_ptr[ip + 1]];
+ text += "\"]";
+
+ incr += 3;
+ } break;
+ case OPCODE_ASSIGN: {
+ text += "assign ";
+ text += DADDR(1);
+ text += " = ";
+ text += DADDR(2);
+
+ incr += 3;
+ } break;
+ case OPCODE_ASSIGN_TRUE: {
+ text += "assign ";
+ text += DADDR(1);
+ text += " = true";
+
+ incr += 2;
+ } break;
+ case OPCODE_ASSIGN_FALSE: {
+ text += "assign ";
+ text += DADDR(1);
+ text += " = false";
+
+ incr += 2;
+ } break;
+ case OPCODE_ASSIGN_TYPED_BUILTIN: {
+ text += "assign typed builtin (";
+ text += Variant::get_type_name((Variant::Type)_code_ptr[ip + 1]);
+ text += ") ";
+ text += DADDR(2);
+ text += " = ";
+ text += DADDR(3);
+
+ incr += 4;
+ } break;
+ case OPCODE_ASSIGN_TYPED_NATIVE: {
+ Variant class_name = _constants_ptr[_code_ptr[ip + 1]];
+ GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(class_name.operator Object *());
+
+ text += "assign typed native (";
+ text += nc->get_name().operator String();
+ text += ") ";
+ text += DADDR(2);
+ text += " = ";
+ text += DADDR(3);
+
+ incr += 4;
+ } break;
+ case OPCODE_ASSIGN_TYPED_SCRIPT: {
+ Variant script = _constants_ptr[_code_ptr[ip + 1]];
+ Script *sc = Object::cast_to<Script>(script.operator Object *());
+
+ text += "assign typed script (";
+ text += sc->get_path();
+ text += ") ";
+ text += DADDR(2);
+ text += " = ";
+ text += DADDR(3);
+
+ incr += 4;
+ } break;
+ case OPCODE_CAST_TO_BUILTIN: {
+ text += "cast builtin ";
+ text += DADDR(3);
+ text += " = ";
+ text += DADDR(2);
+ text += " as ";
+ text += Variant::get_type_name(Variant::Type(_code_ptr[ip + 1]));
+
+ incr += 4;
+ } break;
+ case OPCODE_CAST_TO_NATIVE: {
+ Variant class_name = _constants_ptr[_code_ptr[ip + 1]];
+ GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(class_name.operator Object *());
+
+ text += "cast native ";
+ text += DADDR(3);
+ text += " = ";
+ text += DADDR(2);
+ text += " as ";
+ text += nc->get_name();
+
+ incr += 4;
+ } break;
+ case OPCODE_CAST_TO_SCRIPT: {
+ text += "cast ";
+ text += DADDR(3);
+ text += " = ";
+ text += DADDR(2);
+ text += " as ";
+ text += DADDR(1);
+
+ incr += 4;
+ } break;
+ case OPCODE_CONSTRUCT: {
+ Variant::Type t = Variant::Type(_code_ptr[ip + 1]);
+ int argc = _code_ptr[ip + 2];
+
+ text += "construct ";
+ text += DADDR(3 + argc);
+ text += " = ";
+
+ text += Variant::get_type_name(t) + "(";
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(i + 3);
+ }
+ text += ")";
+
+ incr = 4 + argc;
+ } break;
+ case OPCODE_CONSTRUCT_ARRAY: {
+ int argc = _code_ptr[ip + 1];
+ text += " make_array ";
+ text += DADDR(2 + argc);
+ text += " = [";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(2 + i);
+ }
+
+ text += "]";
+
+ incr += 3 + argc;
+ } break;
+ case OPCODE_CONSTRUCT_DICTIONARY: {
+ int argc = _code_ptr[ip + 1];
+ text += "make_dict ";
+ text += DADDR(2 + argc * 2);
+ text += " = {";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(2 + i * 2 + 0);
+ text += ": ";
+ text += DADDR(2 + i * 2 + 1);
+ }
+
+ text += "}";
+
+ incr += 3 + argc * 2;
+ } break;
+ case OPCODE_CALL:
+ case OPCODE_CALL_RETURN:
+ case OPCODE_CALL_ASYNC: {
+ bool ret = _code_ptr[ip] == OPCODE_CALL_RETURN;
+ bool async = _code_ptr[ip] == OPCODE_CALL_ASYNC;
+
+ if (ret) {
+ text += "call-ret ";
+ } else if (async) {
+ text += "call-async ";
+ } else {
+ text += "call ";
+ }
+
+ int argc = _code_ptr[ip + 1];
+ if (ret || async) {
+ text += DADDR(4 + argc) + " = ";
+ }
+
+ text += DADDR(2) + ".";
+ text += String(_global_names_ptr[_code_ptr[ip + 3]]);
+ text += "(";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(4 + i);
+ }
+ text += ")";
+
+ incr = 5 + argc;
+ } break;
+ case OPCODE_CALL_BUILT_IN: {
+ text += "call-built-in ";
+
+ int argc = _code_ptr[ip + 2];
+ text += DADDR(3 + argc) + " = ";
+
+ text += GDScriptFunctions::get_func_name(GDScriptFunctions::Function(_code_ptr[ip + 1]));
+ text += "(";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(3 + i);
+ }
+ text += ")";
+
+ incr = 4 + argc;
+ } break;
+ case OPCODE_CALL_SELF_BASE: {
+ text += "call-self-base ";
+
+ int argc = _code_ptr[ip + 2];
+ text += DADDR(3 + argc) + " = ";
+
+ text += _global_names_ptr[_code_ptr[ip + 1]];
+ text += "(";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0)
+ text += ", ";
+ text += DADDR(3 + i);
+ }
+ text += ")";
+
+ incr = 4 + argc;
+ } break;
+ case OPCODE_AWAIT: {
+ text += "await ";
+ text += DADDR(1);
+
+ incr += 2;
+ } break;
+ case OPCODE_AWAIT_RESUME: {
+ text += "await resume ";
+ text += DADDR(1);
+
+ incr = 2;
+ } break;
+ case OPCODE_JUMP: {
+ text += "jump ";
+ text += itos(_code_ptr[ip + 1]);
+
+ incr = 2;
+ } break;
+ case OPCODE_JUMP_IF: {
+ text += "jump-if ";
+ text += DADDR(1);
+ text += " to ";
+ text += itos(_code_ptr[ip + 2]);
+
+ incr = 3;
+ } break;
+ case OPCODE_JUMP_IF_NOT: {
+ text += "jump-if-not ";
+ text += DADDR(1);
+ text += " to ";
+ text += itos(_code_ptr[ip + 2]);
+
+ incr = 3;
+ } break;
+ case OPCODE_JUMP_TO_DEF_ARGUMENT: {
+ text += "jump-to-default-argument ";
+
+ incr = 1;
+ } break;
+ case OPCODE_RETURN: {
+ text += "return ";
+ text += DADDR(1);
+
+ incr = 2;
+ } break;
+ case OPCODE_ITERATE_BEGIN: {
+ text += "for-init ";
+ text += DADDR(4);
+ text += " in ";
+ text += DADDR(2);
+ text += " counter ";
+ text += DADDR(1);
+ text += " end ";
+ text += itos(_code_ptr[ip + 3]);
+
+ incr += 5;
+ } break;
+ case OPCODE_ITERATE: {
+ text += "for-loop ";
+ text += DADDR(4);
+ text += " in ";
+ text += DADDR(2);
+ text += " counter ";
+ text += DADDR(1);
+ text += " end ";
+ text += itos(_code_ptr[ip + 3]);
+
+ incr += 5;
+ } break;
+ case OPCODE_LINE: {
+ int line = _code_ptr[ip + 1] - 1;
+ if (line >= 0 && line < p_code_lines.size()) {
+ text += "line ";
+ text += itos(line + 1);
+ text += ": ";
+ text += p_code_lines[line];
+ } else {
+ text += "";
+ }
+
+ incr += 2;
+ } break;
+ case OPCODE_ASSERT: {
+ text += "assert (";
+ text += DADDR(1);
+ text += ", ";
+ text += DADDR(2);
+ text += ")";
+
+ incr += 3;
+ } break;
+ case OPCODE_BREAKPOINT: {
+ text += "breakpoint";
+
+ incr += 1;
+ } break;
+ case OPCODE_END: {
+ text += "== END ==";
+
+ incr += 1;
+ } break;
+ }
+
+ ip += incr;
+ if (text.get_string_length() > 0) {
+ print_line(text.as_string());
+ }
+ }
+}
+#endif
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index 771baf6a08..d1c98a5456 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -182,7 +182,6 @@ public:
OPCODE_CALL_RETURN,
OPCODE_CALL_ASYNC,
OPCODE_CALL_BUILT_IN,
- OPCODE_CALL_SELF,
OPCODE_CALL_SELF_BASE,
OPCODE_AWAIT,
OPCODE_AWAIT_RESUME,
@@ -224,6 +223,7 @@ public:
private:
friend class GDScriptCompiler;
+ friend class GDScriptByteCodeGenerator;
StringName source;
@@ -232,10 +232,6 @@ private:
int _constant_count;
const StringName *_global_names_ptr;
int _global_names_count;
-#ifdef TOOLS_ENABLED
- const StringName *_named_globals_ptr;
- int _named_globals_count;
-#endif
const int *_default_arg_ptr;
int _default_arg_count;
const int *_code_ptr;
@@ -252,9 +248,6 @@ private:
StringName name;
Vector<Variant> constants;
Vector<StringName> global_names;
-#ifdef TOOLS_ENABLED
- Vector<StringName> named_globals;
-#endif
Vector<int> default_arguments;
Vector<int> code;
Vector<GDScriptDataType> argument_types;
@@ -344,6 +337,10 @@ public:
Variant call(GDScriptInstance *p_instance, const Variant **p_args, int p_argcount, Callable::CallError &r_err, CallState *p_state = nullptr);
+#ifdef DEBUG_ENABLED
+ void disassemble(const Vector<String> &p_code_lines) const;
+#endif
+
_FORCE_INLINE_ MultiplayerAPI::RPCMode get_rpc_mode() const { return rpc_mode; }
GDScriptFunction();
~GDScriptFunction();
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
index fefbf906f0..31ce63bc6e 100644
--- a/modules/gdscript/gdscript_functions.cpp
+++ b/modules/gdscript/gdscript_functions.cpp
@@ -635,7 +635,7 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
case TEXT_CHAR: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- CharType result[2] = { *p_args[0], 0 };
+ char32_t result[2] = { *p_args[0], 0 };
r_ret = String(result);
} break;
case TEXT_ORD: {
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index aeec1c0379..e8dea8180a 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -327,7 +327,7 @@ Error GDScriptParser::parse(const String &p_source_code, const String &p_script_
bool found = false;
const String &line = lines[i];
for (int j = 0; j < line.size(); j++) {
- if (line[j] == CharType(0xFFFF)) {
+ if (line[j] == char32_t(0xFFFF)) {
found = true;
break;
} else if (line[j] == '\t') {
@@ -586,6 +586,14 @@ GDScriptParser::ClassNode *GDScriptParser::parse_class() {
return n_class;
}
+ if (match(GDScriptTokenizer::Token::EXTENDS)) {
+ if (n_class->extends_used) {
+ push_error(R"(Cannot use "extends" more than once in the same class.)");
+ }
+ parse_extends();
+ end_statement("superclass");
+ }
+
parse_class_body();
consume(GDScriptTokenizer::Token::DEDENT, R"(Missing unindent at the end of the class body.)");
@@ -631,7 +639,6 @@ void GDScriptParser::parse_extends() {
current_class->extends_path = previous.literal;
if (!match(GDScriptTokenizer::Token::PERIOD)) {
- end_statement("superclass path");
return;
}
}
@@ -1356,7 +1363,7 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
advance();
ReturnNode *n_return = alloc_node<ReturnNode>();
if (!is_statement_end()) {
- if (current_function->identifier->name == GDScriptLanguage::get_singleton()->strings._init) {
+ if (current_function && current_function->identifier->name == GDScriptLanguage::get_singleton()->strings._init) {
push_error(R"(Constructor cannot return a value.)");
}
n_return->return_value = parse_expression(false);
@@ -1469,7 +1476,9 @@ GDScriptParser::ContinueNode *GDScriptParser::parse_continue() {
}
current_suite->has_continue = true;
end_statement(R"("continue")");
- return alloc_node<ContinueNode>();
+ ContinueNode *cont = alloc_node<ContinueNode>();
+ cont->is_for_match = is_continue_match;
+ return cont;
}
GDScriptParser::ForNode *GDScriptParser::parse_for() {
@@ -1488,10 +1497,12 @@ GDScriptParser::ForNode *GDScriptParser::parse_for() {
// Save break/continue state.
bool could_break = can_break;
bool could_continue = can_continue;
+ bool was_continue_match = is_continue_match;
// Allow break/continue.
can_break = true;
can_continue = true;
+ is_continue_match = false;
SuiteNode *suite = alloc_node<SuiteNode>();
if (n_for->variable) {
@@ -1504,6 +1515,7 @@ GDScriptParser::ForNode *GDScriptParser::parse_for() {
// Reset break/continue state.
can_break = could_break;
can_continue = could_continue;
+ is_continue_match = was_continue_match;
return n_for;
}
@@ -1638,8 +1650,10 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() {
// Save continue state.
bool could_continue = can_continue;
+ bool was_continue_match = is_continue_match;
// Allow continue for match.
can_continue = true;
+ is_continue_match = true;
SuiteNode *suite = alloc_node<SuiteNode>();
if (branch->patterns.size() > 0) {
@@ -1656,6 +1670,7 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() {
// Restore continue state.
can_continue = could_continue;
+ is_continue_match = was_continue_match;
return branch;
}
@@ -1813,16 +1828,19 @@ GDScriptParser::WhileNode *GDScriptParser::parse_while() {
// Save break/continue state.
bool could_break = can_break;
bool could_continue = can_continue;
+ bool was_continue_match = is_continue_match;
// Allow break/continue.
can_break = true;
can_continue = true;
+ is_continue_match = false;
n_while->loop = parse_suite(R"("while" block)");
// Reset break/continue state.
can_break = could_break;
can_continue = could_continue;
+ is_continue_match = was_continue_match;
return n_while;
}
@@ -1942,8 +1960,8 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_literal(ExpressionNode *p_
}
GDScriptParser::ExpressionNode *GDScriptParser::parse_self(ExpressionNode *p_previous_operand, bool p_can_assign) {
- if (!current_function || current_function->is_static) {
- push_error(R"(Cannot use "self" outside a non-static function.)");
+ if (current_function && current_function->is_static) {
+ push_error(R"(Cannot use "self" inside a static function.)");
}
SelfNode *self = alloc_node<SelfNode>();
self->current_class = current_class;
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 7d8ae7fc55..4c9473c7bd 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -609,6 +609,7 @@ public:
};
struct ContinueNode : public Node {
+ bool is_for_match = false;
ContinueNode() {
type = CONTINUE;
}
@@ -1079,6 +1080,7 @@ private:
bool panic_mode = false;
bool can_break = false;
bool can_continue = false;
+ bool is_continue_match = false; // Whether a `continue` will act on a `match`.
bool is_ignoring_warnings = false;
List<bool> multiline_stack;
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 737e920693..ed27604aec 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -222,7 +222,7 @@ String GDScriptTokenizer::get_token_name(Token::Type p_token_type) {
void GDScriptTokenizer::set_source_code(const String &p_source_code) {
source = p_source_code;
if (source.empty()) {
- _source = L"";
+ _source = U"";
} else {
_source = source.ptr();
}
@@ -263,7 +263,7 @@ bool GDScriptTokenizer::is_past_cursor() const {
return true;
}
-CharType GDScriptTokenizer::_advance() {
+char32_t GDScriptTokenizer::_advance() {
if (unlikely(_is_at_end())) {
return '\0';
}
@@ -282,15 +282,15 @@ CharType GDScriptTokenizer::_advance() {
return _peek(-1);
}
-void GDScriptTokenizer::push_paren(CharType p_char) {
+void GDScriptTokenizer::push_paren(char32_t p_char) {
paren_stack.push_back(p_char);
}
-bool GDScriptTokenizer::pop_paren(CharType p_expected) {
+bool GDScriptTokenizer::pop_paren(char32_t p_expected) {
if (paren_stack.empty()) {
return false;
}
- CharType actual = paren_stack.back()->get();
+ char32_t actual = paren_stack.back()->get();
paren_stack.pop_back();
return actual == p_expected;
@@ -302,19 +302,19 @@ GDScriptTokenizer::Token GDScriptTokenizer::pop_error() {
return error;
}
-static bool _is_alphanumeric(CharType c) {
+static bool _is_alphanumeric(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
-static bool _is_digit(CharType c) {
+static bool _is_digit(char32_t c) {
return (c >= '0' && c <= '9');
}
-static bool _is_hex_digit(CharType c) {
+static bool _is_hex_digit(char32_t c) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
-static bool _is_binary_digit(CharType c) {
+static bool _is_binary_digit(char32_t c) {
return (c == '0' || c == '1');
}
@@ -404,7 +404,7 @@ void GDScriptTokenizer::push_error(const Token &p_error) {
error_stack.push_back(p_error);
}
-GDScriptTokenizer::Token GDScriptTokenizer::make_paren_error(CharType p_paren) {
+GDScriptTokenizer::Token GDScriptTokenizer::make_paren_error(char32_t p_paren) {
if (paren_stack.empty()) {
return make_error(vformat("Closing \"%c\" doesn't have an opening counterpart.", p_paren));
}
@@ -413,8 +413,8 @@ GDScriptTokenizer::Token GDScriptTokenizer::make_paren_error(CharType p_paren) {
return error;
}
-GDScriptTokenizer::Token GDScriptTokenizer::check_vcs_marker(CharType p_test, Token::Type p_double_type) {
- const CharType *next = _current + 1;
+GDScriptTokenizer::Token GDScriptTokenizer::check_vcs_marker(char32_t p_test, Token::Type p_double_type) {
+ const char32_t *next = _current + 1;
int chars = 2; // Two already matched.
// Test before consuming characters, since we don't want to consume more than needed.
@@ -602,7 +602,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() {
bool has_decimal = false;
bool has_exponent = false;
bool has_error = false;
- bool (*digit_check_func)(CharType) = _is_digit;
+ bool (*digit_check_func)(char32_t) = _is_digit;
if (_peek(-1) == '.') {
has_decimal = true;
@@ -621,7 +621,19 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() {
}
// Allow '_' to be used in a number, for readability.
+ bool previous_was_underscore = false;
while (digit_check_func(_peek()) || _peek() == '_') {
+ if (_peek() == '_') {
+ if (previous_was_underscore) {
+ Token error = make_error(R"(Only one underscore can be used as a numeric separator.)");
+ error.start_column = column;
+ error.leftmost_column = column;
+ error.end_column = column + 1;
+ error.rightmost_column = column + 1;
+ push_error(error);
+ }
+ previous_was_underscore = true;
+ }
_advance();
}
@@ -672,7 +684,27 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() {
_advance();
}
// Consume exponent digits.
+ if (!_is_digit(_peek())) {
+ Token error = make_error(R"(Expected exponent value after "e".)");
+ error.start_column = column;
+ error.leftmost_column = column;
+ error.end_column = column + 1;
+ error.rightmost_column = column + 1;
+ push_error(error);
+ }
+ previous_was_underscore = false;
while (_is_digit(_peek()) || _peek() == '_') {
+ if (_peek() == '_') {
+ if (previous_was_underscore) {
+ Token error = make_error(R"(Only one underscore can be used as a numeric separator.)");
+ error.start_column = column;
+ error.leftmost_column = column;
+ error.end_column = column + 1;
+ error.rightmost_column = column + 1;
+ push_error(error);
+ }
+ previous_was_underscore = true;
+ }
_advance();
}
}
@@ -730,7 +762,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() {
_advance();
}
- CharType quote_char = _peek(-1);
+ char32_t quote_char = _peek(-1);
if (_peek() == quote_char && _peek(1) == quote_char) {
is_multiline = true;
@@ -747,7 +779,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() {
return make_error("Unterminated string.");
}
- CharType ch = _peek();
+ char32_t ch = _peek();
if (ch == '\\') {
// Escape pattern.
@@ -757,13 +789,13 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() {
}
// Grab escape character.
- CharType code = _peek();
+ char32_t code = _peek();
_advance();
if (_is_at_end()) {
return make_error("Unterminated string.");
}
- CharType escaped = 0;
+ char32_t escaped = 0;
bool valid_escape = true;
switch (code) {
@@ -804,8 +836,8 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() {
return make_error("Unterminated string.");
}
- CharType digit = _peek();
- CharType value = 0;
+ char32_t digit = _peek();
+ char32_t value = 0;
if (digit >= '0' && digit <= '9') {
value = digit - '0';
} else if (digit >= 'a' && digit <= 'f') {
@@ -908,7 +940,7 @@ void GDScriptTokenizer::check_indent() {
}
for (;;) {
- CharType current_indent_char = _peek();
+ char32_t current_indent_char = _peek();
int indent_count = 0;
if (current_indent_char != ' ' && current_indent_char != '\t' && current_indent_char != '\r' && current_indent_char != '\n' && current_indent_char != '#') {
@@ -938,7 +970,7 @@ void GDScriptTokenizer::check_indent() {
// Check indent level.
bool mixed = false;
while (!_is_at_end()) {
- CharType space = _peek();
+ char32_t space = _peek();
if (space == '\t') {
// Consider individual tab columns.
column += tab_size - 1;
@@ -1007,7 +1039,7 @@ void GDScriptTokenizer::check_indent() {
// First time indenting, choose character now.
indent_char = current_indent_char;
} else if (current_indent_char != indent_char) {
- Token error = make_error(vformat("Used \"%c\" for indentation instead \"%c\" as used before in the file.", String(&current_indent_char, 1).c_escape(), String(&indent_char, 1).c_escape()));
+ Token error = make_error(vformat("Used \"%s\" for indentation instead \"%s\" as used before in the file.", String(&current_indent_char, 1).c_escape(), String(&indent_char, 1).c_escape()));
error.start_line = line;
error.start_column = 1;
error.leftmost_column = 1;
@@ -1071,7 +1103,7 @@ void GDScriptTokenizer::_skip_whitespace() {
}
for (;;) {
- CharType c = _peek();
+ char32_t c = _peek();
switch (c) {
case ' ':
_advance();
@@ -1160,7 +1192,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() {
return make_token(Token::TK_EOF);
}
- const CharType c = _advance();
+ const char32_t c = _advance();
if (c == '\\') {
// Line continuation with backslash.
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index 100ed3f132..4453982d08 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/modules/gdscript/gdscript_tokenizer.h
@@ -183,14 +183,14 @@ public:
private:
String source;
- const CharType *_source = nullptr;
- const CharType *_current = nullptr;
+ const char32_t *_source = nullptr;
+ const char32_t *_current = nullptr;
int line = -1, column = -1;
int cursor_line = -1, cursor_column = -1;
int tab_size = 4;
// Keep track of multichar tokens.
- const CharType *_start = nullptr;
+ const char32_t *_start = nullptr;
int start_line = 0, start_column = 0;
int leftmost_column = 0, rightmost_column = 0;
@@ -202,30 +202,30 @@ private:
Token last_newline;
int pending_indents = 0;
List<int> indent_stack;
- List<CharType> paren_stack;
- CharType indent_char = '\0';
+ List<char32_t> paren_stack;
+ char32_t indent_char = '\0';
int position = 0;
int length = 0;
_FORCE_INLINE_ bool _is_at_end() { return position >= length; }
- _FORCE_INLINE_ CharType _peek(int p_offset = 0) { return position + p_offset >= 0 && position + p_offset < length ? _current[p_offset] : '\0'; }
+ _FORCE_INLINE_ char32_t _peek(int p_offset = 0) { return position + p_offset >= 0 && position + p_offset < length ? _current[p_offset] : '\0'; }
int indent_level() const { return indent_stack.size(); }
bool has_error() const { return !error_stack.empty(); }
Token pop_error();
- CharType _advance();
+ char32_t _advance();
void _skip_whitespace();
void check_indent();
Token make_error(const String &p_message);
void push_error(const String &p_message);
void push_error(const Token &p_error);
- Token make_paren_error(CharType p_paren);
+ Token make_paren_error(char32_t p_paren);
Token make_token(Token::Type p_type);
Token make_literal(const Variant &p_literal);
Token make_identifier(const StringName &p_identifier);
- Token check_vcs_marker(CharType p_test, Token::Type p_double_type);
- void push_paren(CharType p_char);
- bool pop_paren(CharType p_expected);
+ Token check_vcs_marker(char32_t p_test, Token::Type p_double_type);
+ void push_paren(char32_t p_char);
+ bool pop_paren(char32_t p_expected);
void newline(bool p_make_token);
Token number();
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp
index 4d79d9d395..668dfd4835 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.cpp
+++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp
@@ -491,7 +491,7 @@ String ExtendGDScriptParser::get_identifier_under_position(const lsp::Position &
int start_pos = p_position.character;
for (int c = p_position.character; c >= 0; c--) {
start_pos = c;
- CharType ch = line[c];
+ char32_t ch = line[c];
bool valid_char = (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_';
if (!valid_char) {
break;
@@ -500,7 +500,7 @@ String ExtendGDScriptParser::get_identifier_under_position(const lsp::Position &
int end_pos = p_position.character;
for (int c = p_position.character; c < line.length(); c++) {
- CharType ch = line[c];
+ char32_t ch = line[c];
bool valid_char = (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_';
if (!valid_char) {
break;
@@ -552,7 +552,7 @@ Error ExtendGDScriptParser::get_left_function_call(const lsp::Position &p_positi
}
while (c >= 0) {
- const CharType &character = line[c];
+ const char32_t &character = line[c];
if (character == ')') {
++bracket_stack;
} else if (character == '(') {
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index c554cbac05..7dad878eb1 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -39,6 +39,11 @@
#include "gdscript_cache.h"
#include "gdscript_tokenizer.h"
+#ifdef TESTS_ENABLED
+#include "tests/test_gdscript.h"
+#include "tests/test_macros.h"
+#endif
+
GDScriptLanguage *script_language_gd = nullptr;
Ref<ResourceFormatLoaderGDScript> resource_loader_gd;
Ref<ResourceFormatSaverGDScript> resource_saver_gd;
@@ -153,3 +158,26 @@ void unregister_gdscript_types() {
GDScriptParser::cleanup();
GDScriptAnalyzer::cleanup();
}
+
+#ifdef TESTS_ENABLED
+void test_tokenizer() {
+ TestGDScript::test(TestGDScript::TestType::TEST_TOKENIZER);
+}
+
+void test_parser() {
+ TestGDScript::test(TestGDScript::TestType::TEST_PARSER);
+}
+
+void test_compiler() {
+ TestGDScript::test(TestGDScript::TestType::TEST_COMPILER);
+}
+
+void test_bytecode() {
+ TestGDScript::test(TestGDScript::TestType::TEST_BYTECODE);
+}
+
+REGISTER_TEST_COMMAND("gdscript-tokenizer", &test_tokenizer);
+REGISTER_TEST_COMMAND("gdscript-parser", &test_parser);
+REGISTER_TEST_COMMAND("gdscript-compiler", &test_compiler);
+REGISTER_TEST_COMMAND("gdscript-bytecode", &test_bytecode);
+#endif
diff --git a/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp
index a50311972f..68d9984b43 100644
--- a/tests/test_gdscript.cpp
+++ b/modules/gdscript/tests/test_gdscript.cpp
@@ -35,9 +35,8 @@
#include "core/os/os.h"
#include "core/string_builder.h"
-#include "modules/modules_enabled.gen.h"
-#ifdef MODULE_GDSCRIPT_ENABLED
-
+#include "modules/gdscript/gdscript_analyzer.h"
+#include "modules/gdscript/gdscript_compiler.h"
#include "modules/gdscript/gdscript_parser.h"
#include "modules/gdscript/gdscript_tokenizer.h"
@@ -122,21 +121,79 @@ static void test_parser(const String &p_code, const String &p_script_path, const
printer.print_tree(parser);
}
-MainLoop *test(TestType p_type) {
+static void test_compiler(const String &p_code, const String &p_script_path, const Vector<String> &p_lines) {
+ GDScriptParser parser;
+ Error err = parser.parse(p_code, p_script_path, false);
+
+ if (err != OK) {
+ print_line("Error in parser:");
+ const List<GDScriptParser::ParserError> &errors = parser.get_errors();
+ for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E != nullptr; E = E->next()) {
+ const GDScriptParser::ParserError &error = E->get();
+ print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message));
+ }
+ return;
+ }
+
+ GDScriptAnalyzer analyzer(&parser);
+ err = analyzer.analyze();
+
+ if (err != OK) {
+ print_line("Error in analyzer:");
+ const List<GDScriptParser::ParserError> &errors = parser.get_errors();
+ for (const List<GDScriptParser::ParserError>::Element *E = errors.front(); E != nullptr; E = E->next()) {
+ const GDScriptParser::ParserError &error = E->get();
+ print_line(vformat("%02d:%02d: %s", error.line, error.column, error.message));
+ }
+ return;
+ }
+
+ GDScriptCompiler compiler;
+ Ref<GDScript> script;
+ script.instance();
+ script->set_path(p_script_path);
+
+ err = compiler.compile(&parser, script.ptr(), false);
+
+ if (err) {
+ print_line("Error in compiler:");
+ print_line(vformat("%02d:%02d: %s", compiler.get_error_line(), compiler.get_error_column(), compiler.get_error()));
+ return;
+ }
+
+ for (const Map<StringName, GDScriptFunction *>::Element *E = script->get_member_functions().front(); E; E = E->next()) {
+ const GDScriptFunction *func = E->value();
+
+ String signature = "Disassembling " + func->get_name().operator String() + "(";
+ for (int i = 0; i < func->get_argument_count(); i++) {
+ if (i > 0) {
+ signature += ", ";
+ }
+ signature += func->get_argument_name(i);
+ }
+ print_line(signature + ")");
+
+ func->disassemble(p_lines);
+ print_line("");
+ print_line("");
+ }
+}
+
+void test(TestType p_type) {
List<String> cmdlargs = OS::get_singleton()->get_cmdline_args();
if (cmdlargs.empty()) {
- return nullptr;
+ return;
}
String test = cmdlargs.back()->get();
if (!test.ends_with(".gd")) {
print_line("This test expects a path to a GDScript file as its last parameter. Got: " + test);
- return nullptr;
+ return;
}
FileAccessRef fa = FileAccess::open(test, FileAccess::READ);
- ERR_FAIL_COND_V_MSG(!fa, nullptr, "Could not open file: " + test);
+ ERR_FAIL_COND_MSG(!fa, "Could not open file: " + test);
Vector<uint8_t> buf;
int flen = fa->get_len();
@@ -164,24 +221,11 @@ MainLoop *test(TestType p_type) {
test_parser(code, test, lines);
break;
case TEST_COMPILER:
+ test_compiler(code, test, lines);
+ break;
case TEST_BYTECODE:
print_line("Not implemented.");
}
-
- return nullptr;
-}
-
-} // namespace TestGDScript
-
-#else
-
-namespace TestGDScript {
-
-MainLoop *test(TestType p_type) {
- ERR_PRINT("The GDScript module is disabled, therefore GDScript tests cannot be used.");
- return nullptr;
}
} // namespace TestGDScript
-
-#endif
diff --git a/tests/test_gdscript.h b/modules/gdscript/tests/test_gdscript.h
index 6595da1430..5aa962dcf8 100644
--- a/tests/test_gdscript.h
+++ b/modules/gdscript/tests/test_gdscript.h
@@ -31,8 +31,6 @@
#ifndef TEST_GDSCRIPT_H
#define TEST_GDSCRIPT_H
-#include "core/os/main_loop.h"
-
namespace TestGDScript {
enum TestType {
@@ -42,7 +40,8 @@ enum TestType {
TEST_BYTECODE,
};
-MainLoop *test(TestType p_type);
+void test(TestType p_type);
+
} // namespace TestGDScript
#endif // TEST_GDSCRIPT_H
diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index 79220da7c2..57fbc5bfc0 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -10,7 +10,7 @@
Internally, a GridMap is split into a sparse collection of octants for efficient rendering and physics processing. Every octant has the same dimensions and can contain several cells.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/tutorials/3d/using_gridmaps.html</link>
+ <link title="Using gridmaps">https://docs.godotengine.org/en/latest/tutorials/3d/using_gridmaps.html</link>
</tutorials>
<methods>
<method name="clear">
@@ -205,7 +205,7 @@
GridMaps act as static bodies, meaning they aren't affected by gravity or other forces. They only affect other physics bodies that collide with them.
</member>
<member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The physics layers this GridMap detects collisions in.
+ The physics layers this GridMap detects collisions in. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
<member name="mesh_library" type="MeshLibrary" setter="set_mesh_library" getter="get_mesh_library">
The assigned [MeshLibrary].
diff --git a/modules/mono/build_scripts/mono_reg_utils.py b/modules/mono/build_scripts/mono_reg_utils.py
index 3090a4759a..0ec7e2f433 100644
--- a/modules/mono/build_scripts/mono_reg_utils.py
+++ b/modules/mono/build_scripts/mono_reg_utils.py
@@ -9,7 +9,7 @@ if os.name == "nt":
def _reg_open_key(key, subkey):
try:
return winreg.OpenKey(key, subkey)
- except (WindowsError, OSError):
+ except OSError:
if platform.architecture()[0] == "32bit":
bitness_sam = winreg.KEY_WOW64_64KEY
else:
@@ -37,7 +37,7 @@ def _find_mono_in_reg(subkey, bits):
with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey:
value = winreg.QueryValueEx(hKey, "SdkInstallRoot")[0]
return value
- except (WindowsError, OSError):
+ except OSError:
return None
@@ -48,7 +48,7 @@ def _find_mono_in_reg_old(subkey, bits):
if default_clr:
return _find_mono_in_reg(subkey + "\\" + default_clr, bits)
return None
- except (WindowsError, EnvironmentError):
+ except OSError:
return None
@@ -97,7 +97,7 @@ def find_msbuild_tools_path_reg():
raise ValueError("Cannot find `installationPath` entry")
except ValueError as e:
print("Error reading output from vswhere: " + e.message)
- except WindowsError:
+ except OSError:
pass # Fine, vswhere not found
except (subprocess.CalledProcessError, OSError):
pass
@@ -109,5 +109,5 @@ def find_msbuild_tools_path_reg():
with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, subkey) as hKey:
value = winreg.QueryValueEx(hKey, "MSBuildToolsPath")[0]
return value
- except (WindowsError, OSError):
+ except OSError:
return ""
diff --git a/modules/mono/doc_classes/CSharpScript.xml b/modules/mono/doc_classes/CSharpScript.xml
index e1e9d1381f..45a6f991bf 100644
--- a/modules/mono/doc_classes/CSharpScript.xml
+++ b/modules/mono/doc_classes/CSharpScript.xml
@@ -8,7 +8,7 @@
See also [GodotSharp].
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/getting_started/scripting/c_sharp/index.html</link>
+ <link title="C# tutorial index">https://docs.godotengine.org/en/latest/getting_started/scripting/c_sharp/index.html</link>
</tutorials>
<methods>
<method name="new" qualifiers="vararg">
diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs
index e6b0e8f1df..05e06babd4 100644
--- a/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs
@@ -14,14 +14,18 @@ namespace GodotTools.Core
if (Path.DirectorySeparatorChar == '\\')
dir = dir.Replace("/", "\\") + "\\";
- Uri fullPath = new Uri(Path.GetFullPath(path), UriKind.Absolute);
- Uri relRoot = new Uri(Path.GetFullPath(dir), UriKind.Absolute);
+ var fullPath = new Uri(Path.GetFullPath(path), UriKind.Absolute);
+ var relRoot = new Uri(Path.GetFullPath(dir), UriKind.Absolute);
- return relRoot.MakeRelativeUri(fullPath).ToString();
+ // MakeRelativeUri converts spaces to %20, hence why we need UnescapeDataString
+ return Uri.UnescapeDataString(relRoot.MakeRelativeUri(fullPath).ToString());
}
public static string NormalizePath(this string path)
{
+ if (string.IsNullOrEmpty(path))
+ return path;
+
bool rooted = path.IsAbsolutePath();
path = path.Replace('\\', '/');
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj
index 41c94f19c8..e4d6b2e010 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj
@@ -20,7 +20,7 @@
<ItemGroup>
<None Include="MSBuild.exe" CopyToOutputDirectory="Always" />
</ItemGroup>
- <Target Name="CopyMSBuildStubWindows" AfterTargets="Build" Condition="$([MSBuild]::IsOsPlatform(Windows))">
+ <Target Name="CopyMSBuildStubWindows" AfterTargets="Build" Condition=" '$(GodotPlatform)' == 'windows' Or ( '$(GodotPlatform)' == '' And '$(OS)' == 'Windows_NT' ) ">
<PropertyGroup>
<GodotSourceRootPath>$(SolutionDir)/../../../../</GodotSourceRootPath>
<GodotOutputDataDir>$(GodotSourceRootPath)/bin/GodotSharp</GodotOutputDataDir>
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
index 4041c56597..4e2c0f17cc 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
@@ -61,10 +61,9 @@ namespace GodotTools.ProjectEditor
if (item.ItemType != itemType)
continue;
- string normalizedExclude = item.Exclude.NormalizePath();
-
- var glob = MSBuildGlob.Parse(normalizedExclude);
+ string normalizedRemove = item.Remove.NormalizePath();
+ var glob = MSBuildGlob.Parse(normalizedRemove);
excluded.AddRange(includedFiles.Where(includedFile => glob.IsMatch(includedFile)));
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs
index f36e581a5f..7bfba779fb 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs
@@ -161,8 +161,21 @@ namespace GodotTools.Build
// Try to find 15.0 with vswhere
- string vsWherePath = Environment.GetEnvironmentVariable(Internal.GodotIs32Bits() ? "ProgramFiles" : "ProgramFiles(x86)");
- vsWherePath += "\\Microsoft Visual Studio\\Installer\\vswhere.exe";
+ var envNames = Internal.GodotIs32Bits() ? new[] { "ProgramFiles", "ProgramW6432" } : new[] { "ProgramFiles(x86)", "ProgramFiles" };
+
+ string vsWherePath = null;
+ foreach (var envName in envNames)
+ {
+ vsWherePath = Environment.GetEnvironmentVariable(envName);
+ if (!string.IsNullOrEmpty(vsWherePath))
+ {
+ vsWherePath += "\\Microsoft Visual Studio\\Installer\\vswhere.exe";
+ if (File.Exists(vsWherePath))
+ break;
+ }
+
+ vsWherePath = null;
+ }
var vsWhereArgs = new[] {"-latest", "-products", "*", "-requires", "Microsoft.Component.MSBuild"};
diff --git a/modules/mono/editor/GodotTools/GodotTools/CsProjOperations.cs b/modules/mono/editor/GodotTools/GodotTools/CsProjOperations.cs
index a8afb38728..1d800b8151 100644
--- a/modules/mono/editor/GodotTools/GodotTools/CsProjOperations.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/CsProjOperations.cs
@@ -48,7 +48,7 @@ namespace GodotTools
var firstMatch = classes.FirstOrDefault(classDecl =>
classDecl.BaseCount != 0 && // If it doesn't inherit anything, it can't be a Godot.Object.
- classDecl.SearchName != searchName // Filter by the name we're looking for
+ classDecl.SearchName == searchName // Filter by the name we're looking for
);
if (firstMatch == null)
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index e819848212..599ca94699 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
@@ -19,7 +19,7 @@ namespace GodotTools.Export
public class ExportPlugin : EditorExportPlugin
{
[Flags]
- enum I18NCodesets
+ enum I18NCodesets : long
{
None = 0,
CJK = 1,
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index 3148458d7e..2a450c5b87 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -31,6 +31,7 @@ namespace GodotTools
private CheckBox aboutDialogCheckBox;
private Button bottomPanelBtn;
+ private Button toolBarBuildButton;
public GodotIdeManager GodotIdeManager { get; private set; }
@@ -127,6 +128,7 @@ namespace GodotTools
{
menuPopup.RemoveItem(menuPopup.GetItemIndex((int)MenuOptions.CreateSln));
bottomPanelBtn.Show();
+ toolBarBuildButton.Show();
}
private void _ShowAboutDialog()
@@ -468,6 +470,15 @@ namespace GodotTools
aboutVBox.AddChild(aboutDialogCheckBox);
}
+ toolBarBuildButton = new Button
+ {
+ Text = "Build",
+ HintTooltip = "Build solution",
+ FocusMode = Control.FocusModeEnum.None
+ };
+ toolBarBuildButton.PressedSignal += _BuildSolutionPressed;
+ AddControlToContainer(CustomControlContainer.Toolbar, toolBarBuildButton);
+
if (File.Exists(GodotSharpDirs.ProjectSlnPath) && File.Exists(GodotSharpDirs.ProjectCsProjPath))
{
ApplyNecessaryChangesToSolution();
@@ -475,20 +486,12 @@ namespace GodotTools
else
{
bottomPanelBtn.Hide();
+ toolBarBuildButton.Hide();
menuPopup.AddItem("Create C# solution".TTR(), (int)MenuOptions.CreateSln);
}
menuPopup.IdPressed += _MenuOptionPressed;
- var buildButton = new Button
- {
- Text = "Build",
- HintTooltip = "Build solution",
- FocusMode = Control.FocusModeEnum.None
- };
- buildButton.PressedSignal += _BuildSolutionPressed;
- AddControlToContainer(CustomControlContainer.Toolbar, buildButton);
-
// External editor settings
EditorDef("mono/editor/external_editor", ExternalEditorId.None);
diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp
index b15e9b060a..2edd8c87dc 100644
--- a/modules/mono/editor/godotsharp_export.cpp
+++ b/modules/mono/editor/godotsharp_export.cpp
@@ -43,6 +43,16 @@
namespace GodotSharpExport {
+MonoAssemblyName *new_mono_assembly_name() {
+ // Mono has no public API to create an empty MonoAssemblyName and the struct is private.
+ // As such the only way to create it is with a stub name and then clear it.
+
+ MonoAssemblyName *aname = mono_assembly_name_new("stub");
+ CRASH_COND(aname == nullptr);
+ mono_assembly_name_free(aname); // Frees the string fields, not the struct
+ return aname;
+}
+
struct AssemblyRefInfo {
String name;
uint16_t major;
@@ -67,7 +77,7 @@ AssemblyRefInfo get_assemblyref_name(MonoImage *p_image, int index) {
};
}
-Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Dictionary &r_assembly_dependencies) {
+Error get_assembly_dependencies(GDMonoAssembly *p_assembly, MonoAssemblyName *reusable_aname, const Vector<String> &p_search_dirs, Dictionary &r_assembly_dependencies) {
MonoImage *image = p_assembly->get_image();
for (int i = 0; i < mono_image_get_table_rows(image, MONO_TABLE_ASSEMBLYREF); i++) {
@@ -79,26 +89,16 @@ Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String>
continue;
}
- GDMonoAssembly *ref_assembly = nullptr;
-
- {
- MonoAssemblyName *ref_aname = mono_assembly_name_new("A"); // We can't allocate an empty MonoAssemblyName, hence "A"
- CRASH_COND(ref_aname == nullptr);
- SCOPE_EXIT {
- mono_assembly_name_free(ref_aname);
- mono_free(ref_aname);
- };
-
- mono_assembly_get_assemblyref(image, i, ref_aname);
+ mono_assembly_get_assemblyref(image, i, reusable_aname);
- if (!GDMono::get_singleton()->load_assembly(ref_name, ref_aname, &ref_assembly, /* refonly: */ true, p_search_dirs)) {
- ERR_FAIL_V_MSG(ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + ref_name + "'.");
- }
-
- r_assembly_dependencies[ref_name] = ref_assembly->get_path();
+ GDMonoAssembly *ref_assembly = NULL;
+ if (!GDMono::get_singleton()->load_assembly(ref_name, reusable_aname, &ref_assembly, /* refonly: */ true, p_search_dirs)) {
+ ERR_FAIL_V_MSG(ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + ref_name + "'.");
}
- Error err = get_assembly_dependencies(ref_assembly, p_search_dirs, r_assembly_dependencies);
+ r_assembly_dependencies[ref_name] = ref_assembly->get_path();
+
+ Error err = get_assembly_dependencies(ref_assembly, reusable_aname, p_search_dirs, r_assembly_dependencies);
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot load one of the dependencies for the assembly: '" + ref_name + "'.");
}
@@ -130,7 +130,10 @@ Error get_exported_assembly_dependencies(const Dictionary &p_initial_assemblies,
ERR_FAIL_COND_V_MSG(!load_success, ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + assembly_name + "'.");
- Error err = get_assembly_dependencies(assembly, search_dirs, r_assembly_dependencies);
+ MonoAssemblyName *reusable_aname = new_mono_assembly_name();
+ SCOPE_EXIT { mono_free(reusable_aname); };
+
+ Error err = get_assembly_dependencies(assembly, reusable_aname, search_dirs, r_assembly_dependencies);
if (err != OK) {
return err;
}
diff --git a/modules/mono/editor/script_class_parser.cpp b/modules/mono/editor/script_class_parser.cpp
index 430c82953e..f7d6e7e302 100644
--- a/modules/mono/editor/script_class_parser.cpp
+++ b/modules/mono/editor/script_class_parser.cpp
@@ -151,7 +151,7 @@ ScriptClassParser::Token ScriptClassParser::get_token() {
case '"': {
bool verbatim = idx != 0 && code[idx - 1] == '@';
- CharType begin_str = code[idx];
+ char32_t begin_str = code[idx];
idx++;
String tk_string = String();
while (true) {
@@ -170,13 +170,13 @@ ScriptClassParser::Token ScriptClassParser::get_token() {
} else if (code[idx] == '\\' && !verbatim) {
//escaped characters...
idx++;
- CharType next = code[idx];
+ char32_t next = code[idx];
if (next == 0) {
error_str = "Unterminated String";
error = true;
return TK_ERROR;
}
- CharType res = 0;
+ char32_t res = 0;
switch (next) {
case 'b':
@@ -234,7 +234,7 @@ ScriptClassParser::Token ScriptClassParser::get_token() {
if (code[idx] == '-' || (code[idx] >= '0' && code[idx] <= '9')) {
//a number
- const CharType *rptr;
+ const char32_t *rptr;
double number = String::to_float(&code[idx], &rptr);
idx += (rptr - &code[idx]);
value = number;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
index d851abc6d3..3700a6194f 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
@@ -565,6 +565,9 @@ namespace Godot
rgba = rgba.Substring(1);
}
+ // If enabled, use 1 hex digit per channel instead of 2.
+ // Other sizes aren't in the HTML/CSS spec but we could add them if desired.
+ bool isShorthand = rgba.Length < 5;
bool alpha;
if (rgba.Length == 8)
@@ -575,47 +578,60 @@ namespace Godot
{
alpha = false;
}
+ else if (rgba.Length == 4)
+ {
+ alpha = true;
+ }
+ else if (rgba.Length == 3)
+ {
+ alpha = false;
+ }
else
{
throw new ArgumentOutOfRangeException("Invalid color code. Length is " + rgba.Length + " but a length of 6 or 8 is expected: " + rgba);
}
- if (alpha)
+ a = 1.0f;
+ if (isShorthand)
{
- a = ParseCol8(rgba, 6) / 255f;
-
- if (a < 0)
+ r = ParseCol4(rgba, 0) / 15f;
+ g = ParseCol4(rgba, 1) / 15f;
+ b = ParseCol4(rgba, 2) / 15f;
+ if (alpha)
{
- throw new ArgumentOutOfRangeException("Invalid color code. Alpha part is not valid hexadecimal: " + rgba);
+ a = ParseCol4(rgba, 3) / 15f;
}
}
else
{
- a = 1.0f;
+ r = ParseCol8(rgba, 0) / 255f;
+ g = ParseCol8(rgba, 2) / 255f;
+ b = ParseCol8(rgba, 4) / 255f;
+ if (alpha)
+ {
+ a = ParseCol8(rgba, 6) / 255f;
+ }
}
- int from = alpha ? 2 : 0;
-
- r = ParseCol8(rgba, 0) / 255f;
-
if (r < 0)
{
throw new ArgumentOutOfRangeException("Invalid color code. Red part is not valid hexadecimal: " + rgba);
}
- g = ParseCol8(rgba, 2) / 255f;
-
if (g < 0)
{
throw new ArgumentOutOfRangeException("Invalid color code. Green part is not valid hexadecimal: " + rgba);
}
- b = ParseCol8(rgba, 4) / 255f;
-
if (b < 0)
{
throw new ArgumentOutOfRangeException("Invalid color code. Blue part is not valid hexadecimal: " + rgba);
}
+
+ if (a < 0)
+ {
+ throw new ArgumentOutOfRangeException("Invalid color code. Alpha part is not valid hexadecimal: " + rgba);
+ }
}
/// <summary>
@@ -751,45 +767,28 @@ namespace Godot
value = max;
}
- private static int ParseCol8(string str, int ofs)
+ private static int ParseCol4(string str, int ofs)
{
- int ig = 0;
+ char character = str[ofs];
- for (int i = 0; i < 2; i++)
+ if (character >= '0' && character <= '9')
{
- int c = str[i + ofs];
- int v;
-
- if (c >= '0' && c <= '9')
- {
- v = c - '0';
- }
- else if (c >= 'a' && c <= 'f')
- {
- v = c - 'a';
- v += 10;
- }
- else if (c >= 'A' && c <= 'F')
- {
- v = c - 'A';
- v += 10;
- }
- else
- {
- return -1;
- }
-
- if (i == 0)
- {
- ig += v * 16;
- }
- else
- {
- ig += v;
- }
+ return character - '0';
+ }
+ else if (character >= 'a' && character <= 'f')
+ {
+ return character + (10 - 'a');
}
+ else if (character >= 'A' && character <= 'F')
+ {
+ return character + (10 - 'A');
+ }
+ return -1;
+ }
- return ig;
+ private static int ParseCol8(string str, int ofs)
+ {
+ return ParseCol4(str, ofs) * 16 + ParseCol4(str, ofs + 1);
}
private String ToHex32(float val)
@@ -828,46 +827,24 @@ namespace Godot
if (color[0] == '#')
{
- color = color.Substring(1, color.Length - 1);
+ color = color.Substring(1);
}
- bool alpha;
-
- switch (color.Length)
+ // Check if the amount of hex digits is valid.
+ int len = color.Length;
+ if (!(len == 3 || len == 4 || len == 6 || len == 8))
{
- case 8:
- alpha = true;
- break;
- case 6:
- alpha = false;
- break;
- default:
- return false;
+ return false;
}
- if (alpha)
- {
- if (ParseCol8(color, 0) < 0)
+ // Check if each hex digit is valid.
+ for (int i = 0; i < len; i++) {
+ if (ParseCol4(color, i) == -1)
{
return false;
}
}
- int from = alpha ? 2 : 0;
-
- if (ParseCol8(color, from + 0) < 0)
- {
- return false;
- }
- if (ParseCol8(color, from + 2) < 0)
- {
- return false;
- }
- if (ParseCol8(color, from + 4) < 0)
- {
- return false;
- }
-
return true;
}
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index 9dbeee57ce..6d7b771fd3 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -464,7 +464,9 @@ GDMonoAssembly *GDMonoAssembly::load(const String &p_name, MonoAssemblyName *p_a
if (!assembly) {
assembly = _load_assembly_search(p_name, p_aname, p_refonly, p_search_dirs);
- ERR_FAIL_NULL_V(assembly, nullptr);
+ if (!assembly) {
+ return nullptr;
+ }
}
GDMonoAssembly *loaded_asm = GDMono::get_singleton()->get_loaded_assembly(p_name);
@@ -487,7 +489,9 @@ GDMonoAssembly *GDMonoAssembly::load_from(const String &p_name, const String &p_
if (!assembly) {
assembly = _real_load_assembly_from(p_path, p_refonly);
- ERR_FAIL_NULL_V(assembly, nullptr);
+ if (!assembly) {
+ return nullptr;
+ }
}
GDMonoAssembly *loaded_asm = GDMono::get_singleton()->get_loaded_assembly(p_name);
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index 6d7d5f76cd..c460e283ea 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -311,44 +311,6 @@ bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_
return false;
}
-String mono_to_utf8_string(MonoString *p_mono_string) {
- MonoError error;
- char *utf8 = mono_string_to_utf8_checked(p_mono_string, &error);
-
- if (!mono_error_ok(&error)) {
- ERR_PRINT(String() + "Failed to convert MonoString* to UTF-8: '" + mono_error_get_message(&error) + "'.");
- mono_error_cleanup(&error);
- return String();
- }
-
- String ret = String::utf8(utf8);
-
- mono_free(utf8);
-
- return ret;
-}
-
-String mono_to_utf16_string(MonoString *p_mono_string) {
- int len = mono_string_length(p_mono_string);
- String ret;
-
- if (len == 0) {
- return ret;
- }
-
- ret.resize(len + 1);
- ret.set(len, 0);
-
- CharType *src = (CharType *)mono_string_chars(p_mono_string);
- CharType *dst = ret.ptrw();
-
- for (int i = 0; i < len; i++) {
- dst[i] = src[i];
- }
-
- return ret;
-}
-
MonoObject *variant_to_mono_object(const Variant *p_var) {
ManagedType type;
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index 4ff330fd43..a1fd975916 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -69,15 +69,11 @@ bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_
// String
-String mono_to_utf8_string(MonoString *p_mono_string);
-String mono_to_utf16_string(MonoString *p_mono_string);
-
_FORCE_INLINE_ String mono_string_to_godot_not_null(MonoString *p_mono_string) {
- if constexpr (sizeof(CharType) == 2) {
- return mono_to_utf16_string(p_mono_string);
- }
-
- return mono_to_utf8_string(p_mono_string);
+ char32_t *utf32 = (char32_t *)mono_string_to_utf32(p_mono_string);
+ String ret = String(utf32);
+ mono_free(utf32);
+ return ret;
}
_FORCE_INLINE_ String mono_string_to_godot(MonoString *p_mono_string) {
@@ -88,20 +84,8 @@ _FORCE_INLINE_ String mono_string_to_godot(MonoString *p_mono_string) {
return mono_string_to_godot_not_null(p_mono_string);
}
-_FORCE_INLINE_ MonoString *mono_from_utf8_string(const String &p_string) {
- return mono_string_new(mono_domain_get(), p_string.utf8().get_data());
-}
-
-_FORCE_INLINE_ MonoString *mono_from_utf16_string(const String &p_string) {
- return mono_string_from_utf16((mono_unichar2 *)p_string.c_str());
-}
-
_FORCE_INLINE_ MonoString *mono_string_from_godot(const String &p_string) {
- if constexpr (sizeof(CharType) == 2) {
- return mono_from_utf16_string(p_string);
- }
-
- return mono_from_utf8_string(p_string);
+ return mono_string_from_utf32((mono_unichar4 *)(p_string.get_data()));
}
// Variant
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index 9db4a5f3f0..5958bf3cc1 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -44,7 +44,8 @@
if (unlikely(m_exc != nullptr)) { \
GDMonoUtils::debug_unhandled_exception(m_exc); \
GD_UNREACHABLE(); \
- }
+ } else \
+ ((void)0)
namespace GDMonoUtils {
@@ -162,20 +163,24 @@ StringName get_native_godot_class_name(GDMonoClass *p_class);
#define GD_MONO_BEGIN_RUNTIME_INVOKE \
int &_runtime_invoke_count_ref = GDMonoUtils::get_runtime_invoke_count_ref(); \
- _runtime_invoke_count_ref += 1;
+ _runtime_invoke_count_ref += 1; \
+ ((void)0)
-#define GD_MONO_END_RUNTIME_INVOKE \
- _runtime_invoke_count_ref -= 1;
+#define GD_MONO_END_RUNTIME_INVOKE \
+ _runtime_invoke_count_ref -= 1; \
+ ((void)0)
#define GD_MONO_SCOPE_THREAD_ATTACH \
GDMonoUtils::ScopeThreadAttach __gdmono__scope__thread__attach__; \
- (void)__gdmono__scope__thread__attach__;
+ (void)__gdmono__scope__thread__attach__; \
+ ((void)0)
#ifdef DEBUG_ENABLED
-#define GD_MONO_ASSERT_THREAD_ATTACHED \
- { CRASH_COND(!GDMonoUtils::is_thread_attached()); }
+#define GD_MONO_ASSERT_THREAD_ATTACHED \
+ CRASH_COND(!GDMonoUtils::is_thread_attached()); \
+ ((void)0)
#else
-#define GD_MONO_ASSERT_THREAD_ATTACHED
+#define GD_MONO_ASSERT_THREAD_ATTACHED ((void)0)
#endif
#endif // GD_MONOUTILS_H
diff --git a/modules/mono/register_types.h b/modules/mono/register_types.h
index 7fd0d24eb0..e30d9a8abd 100644
--- a/modules/mono/register_types.h
+++ b/modules/mono/register_types.h
@@ -28,5 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef MONO_REGISTER_TYPES_H
+#define MONO_REGISTER_TYPES_H
+
void register_mono_types();
void unregister_mono_types();
+
+#endif // MONO_REGISTER_TYPES_H
diff --git a/modules/mono/utils/macros.h b/modules/mono/utils/macros.h
index dc542477f5..c76619cca4 100644
--- a/modules/mono/utils/macros.h
+++ b/modules/mono/utils/macros.h
@@ -46,7 +46,7 @@
#define GD_UNREACHABLE() \
CRASH_NOW(); \
do { \
- } while (true);
+ } while (true)
#endif
namespace gdmono {
diff --git a/modules/mono/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp
index e0cf916a01..a619f0b975 100644
--- a/modules/mono/utils/mono_reg_utils.cpp
+++ b/modules/mono/utils/mono_reg_utils.cpp
@@ -71,12 +71,12 @@ LONG _RegKeyQueryString(HKEY hKey, const String &p_value_name, String &r_value)
buffer.resize(512);
DWORD dwBufferSize = buffer.size();
- LONG res = RegQueryValueExW(hKey, p_value_name.c_str(), 0, nullptr, (LPBYTE)buffer.ptr(), &dwBufferSize);
+ LONG res = RegQueryValueExW(hKey, (LPCWSTR)(p_value_name.utf16().get_data()), 0, nullptr, (LPBYTE)buffer.ptr(), &dwBufferSize);
if (res == ERROR_MORE_DATA) {
// dwBufferSize now contains the actual size
buffer.resize(dwBufferSize);
- res = RegQueryValueExW(hKey, p_value_name.c_str(), 0, nullptr, (LPBYTE)buffer.ptr(), &dwBufferSize);
+ res = RegQueryValueExW(hKey, (LPCWSTR)(p_value_name.utf16().get_data()), 0, nullptr, (LPBYTE)buffer.ptr(), &dwBufferSize);
}
if (res == ERROR_SUCCESS) {
@@ -90,7 +90,7 @@ LONG _RegKeyQueryString(HKEY hKey, const String &p_value_name, String &r_value)
LONG _find_mono_in_reg(const String &p_subkey, MonoRegInfo &r_info, bool p_old_reg = false) {
HKEY hKey;
- LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, p_subkey.c_str(), &hKey);
+ LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, (LPCWSTR)(p_subkey.utf16().get_data()), &hKey);
if (res != ERROR_SUCCESS)
goto cleanup;
@@ -127,7 +127,7 @@ LONG _find_mono_in_reg_old(const String &p_subkey, MonoRegInfo &r_info) {
String default_clr;
HKEY hKey;
- LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, p_subkey.c_str(), &hKey);
+ LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, (LPCWSTR)(p_subkey.utf16().get_data()), &hKey);
if (res != ERROR_SUCCESS)
goto cleanup;
diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp
index ccfaf5aba7..5d1abd0c09 100644
--- a/modules/mono/utils/path_utils.cpp
+++ b/modules/mono/utils/path_utils.cpp
@@ -54,12 +54,16 @@ String cwd() {
#ifdef WINDOWS_ENABLED
const DWORD expected_size = ::GetCurrentDirectoryW(0, nullptr);
- String buffer;
+ Char16String buffer;
buffer.resize((int)expected_size);
- if (::GetCurrentDirectoryW(expected_size, buffer.ptrw()) == 0)
+ if (::GetCurrentDirectoryW(expected_size, (wchar_t *)buffer.ptrw()) == 0)
return ".";
- return buffer.simplify_path();
+ String result;
+ if (result.parse_utf16(buffer.ptr())) {
+ return ".";
+ }
+ return result.simplify_path();
#else
char buffer[PATH_MAX];
if (::getcwd(buffer, sizeof(buffer)) == nullptr) {
@@ -86,7 +90,7 @@ String abspath(const String &p_path) {
String realpath(const String &p_path) {
#ifdef WINDOWS_ENABLED
// Open file without read/write access
- HANDLE hFile = ::CreateFileW(p_path.c_str(), 0,
+ HANDLE hFile = ::CreateFileW((LPCWSTR)(p_path.utf16().get_data()), 0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
@@ -100,12 +104,18 @@ String realpath(const String &p_path) {
return p_path;
}
- String buffer;
+ Char16String buffer;
buffer.resize((int)expected_size);
- ::GetFinalPathNameByHandleW(hFile, buffer.ptrw(), expected_size, FILE_NAME_NORMALIZED);
+ ::GetFinalPathNameByHandleW(hFile, (wchar_t *)buffer.ptrw(), expected_size, FILE_NAME_NORMALIZED);
::CloseHandle(hFile);
- return buffer.simplify_path();
+
+ String result;
+ if (result.parse_utf16(buffer.ptr())) {
+ return p_path;
+ }
+
+ return result.simplify_path();
#elif UNIX_ENABLED
char *resolved_path = ::realpath(p_path.utf8().get_data(), nullptr);
@@ -130,7 +140,7 @@ String join(const String &p_a, const String &p_b) {
return p_b;
}
- const CharType a_last = p_a[p_a.length() - 1];
+ const char32_t a_last = p_a[p_a.length() - 1];
if ((a_last == '/' || a_last == '\\') ||
(p_b.size() > 0 && (p_b[0] == '/' || p_b[0] == '\\'))) {
return p_a + p_b;
diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp
index f8d9804de4..65da4328f6 100644
--- a/modules/mono/utils/string_utils.cpp
+++ b/modules/mono/utils/string_utils.cpp
@@ -49,7 +49,7 @@ int sfind(const String &p_text, int p_from) {
return -1;
}
- const CharType *src = p_text.c_str();
+ const char32_t *src = p_text.get_data();
for (int i = p_from; i <= (len - src_len); i++) {
bool found = true;
@@ -64,7 +64,7 @@ int sfind(const String &p_text, int p_from) {
found = src[read_pos] == '%';
break;
case 1: {
- CharType c = src[read_pos];
+ char32_t c = src[read_pos];
found = src[read_pos] == 's' || (c >= '0' && c <= '4');
break;
}
@@ -121,7 +121,7 @@ String sformat(const String &p_text, const Variant &p1, const Variant &p2, const
int result = 0;
while ((result = sfind(p_text, search_from)) >= 0) {
- CharType c = p_text[result + 1];
+ char32_t c = p_text[result + 1];
int req_index = (c == 's' ? findex++ : c - '0');
diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp
index 50ca01067b..c10a276eae 100644
--- a/modules/regex/regex.cpp
+++ b/modules/regex/regex.cpp
@@ -156,26 +156,13 @@ void RegExMatch::_bind_methods() {
}
void RegEx::_pattern_info(uint32_t what, void *where) const {
- if (sizeof(CharType) == 2) {
- pcre2_pattern_info_16((pcre2_code_16 *)code, what, where);
-
- } else {
- pcre2_pattern_info_32((pcre2_code_32 *)code, what, where);
- }
+ pcre2_pattern_info_32((pcre2_code_32 *)code, what, where);
}
void RegEx::clear() {
- if (sizeof(CharType) == 2) {
- if (code) {
- pcre2_code_free_16((pcre2_code_16 *)code);
- code = nullptr;
- }
-
- } else {
- if (code) {
- pcre2_code_free_32((pcre2_code_32 *)code);
- code = nullptr;
- }
+ if (code) {
+ pcre2_code_free_32((pcre2_code_32 *)code);
+ code = nullptr;
}
}
@@ -187,39 +174,20 @@ Error RegEx::compile(const String &p_pattern) {
PCRE2_SIZE offset;
uint32_t flags = PCRE2_DUPNAMES;
- if (sizeof(CharType) == 2) {
- pcre2_general_context_16 *gctx = (pcre2_general_context_16 *)general_ctx;
- pcre2_compile_context_16 *cctx = pcre2_compile_context_create_16(gctx);
- PCRE2_SPTR16 p = (PCRE2_SPTR16)pattern.c_str();
-
- code = pcre2_compile_16(p, pattern.length(), flags, &err, &offset, cctx);
+ pcre2_general_context_32 *gctx = (pcre2_general_context_32 *)general_ctx;
+ pcre2_compile_context_32 *cctx = pcre2_compile_context_create_32(gctx);
+ PCRE2_SPTR32 p = (PCRE2_SPTR32)pattern.get_data();
- pcre2_compile_context_free_16(cctx);
+ code = pcre2_compile_32(p, pattern.length(), flags, &err, &offset, cctx);
- if (!code) {
- PCRE2_UCHAR16 buf[256];
- pcre2_get_error_message_16(err, buf, 256);
- String message = String::num(offset) + ": " + String((const CharType *)buf);
- ERR_PRINT(message.utf8());
- return FAILED;
- }
+ pcre2_compile_context_free_32(cctx);
- } else {
- pcre2_general_context_32 *gctx = (pcre2_general_context_32 *)general_ctx;
- pcre2_compile_context_32 *cctx = pcre2_compile_context_create_32(gctx);
- PCRE2_SPTR32 p = (PCRE2_SPTR32)pattern.c_str();
-
- code = pcre2_compile_32(p, pattern.length(), flags, &err, &offset, cctx);
-
- pcre2_compile_context_free_32(cctx);
-
- if (!code) {
- PCRE2_UCHAR32 buf[256];
- pcre2_get_error_message_32(err, buf, 256);
- String message = String::num(offset) + ": " + String((const CharType *)buf);
- ERR_PRINT(message.utf8());
- return FAILED;
- }
+ if (!code) {
+ PCRE2_UCHAR32 buf[256];
+ pcre2_get_error_message_32(err, buf, 256);
+ String message = String::num(offset) + ": " + String((const char32_t *)buf);
+ ERR_PRINT(message.utf8());
+ return FAILED;
}
return OK;
}
@@ -234,69 +202,39 @@ Ref<RegExMatch> RegEx::search(const String &p_subject, int p_offset, int p_end)
length = p_end;
}
- if (sizeof(CharType) == 2) {
- pcre2_code_16 *c = (pcre2_code_16 *)code;
- pcre2_general_context_16 *gctx = (pcre2_general_context_16 *)general_ctx;
- pcre2_match_context_16 *mctx = pcre2_match_context_create_16(gctx);
- PCRE2_SPTR16 s = (PCRE2_SPTR16)p_subject.c_str();
-
- pcre2_match_data_16 *match = pcre2_match_data_create_from_pattern_16(c, gctx);
-
- int res = pcre2_match_16(c, s, length, p_offset, 0, match, mctx);
+ pcre2_code_32 *c = (pcre2_code_32 *)code;
+ pcre2_general_context_32 *gctx = (pcre2_general_context_32 *)general_ctx;
+ pcre2_match_context_32 *mctx = pcre2_match_context_create_32(gctx);
+ PCRE2_SPTR32 s = (PCRE2_SPTR32)p_subject.get_data();
- if (res < 0) {
- pcre2_match_data_free_16(match);
- return nullptr;
- }
-
- uint32_t size = pcre2_get_ovector_count_16(match);
- PCRE2_SIZE *ovector = pcre2_get_ovector_pointer_16(match);
-
- result->data.resize(size);
-
- for (uint32_t i = 0; i < size; i++) {
- result->data.write[i].start = ovector[i * 2];
- result->data.write[i].end = ovector[i * 2 + 1];
- }
-
- pcre2_match_data_free_16(match);
- pcre2_match_context_free_16(mctx);
-
- } else {
- pcre2_code_32 *c = (pcre2_code_32 *)code;
- pcre2_general_context_32 *gctx = (pcre2_general_context_32 *)general_ctx;
- pcre2_match_context_32 *mctx = pcre2_match_context_create_32(gctx);
- PCRE2_SPTR32 s = (PCRE2_SPTR32)p_subject.c_str();
+ pcre2_match_data_32 *match = pcre2_match_data_create_from_pattern_32(c, gctx);
- pcre2_match_data_32 *match = pcre2_match_data_create_from_pattern_32(c, gctx);
+ int res = pcre2_match_32(c, s, length, p_offset, 0, match, mctx);
- int res = pcre2_match_32(c, s, length, p_offset, 0, match, mctx);
-
- if (res < 0) {
- pcre2_match_data_free_32(match);
- pcre2_match_context_free_32(mctx);
+ if (res < 0) {
+ pcre2_match_data_free_32(match);
+ pcre2_match_context_free_32(mctx);
- return nullptr;
- }
+ return nullptr;
+ }
- uint32_t size = pcre2_get_ovector_count_32(match);
- PCRE2_SIZE *ovector = pcre2_get_ovector_pointer_32(match);
+ uint32_t size = pcre2_get_ovector_count_32(match);
+ PCRE2_SIZE *ovector = pcre2_get_ovector_pointer_32(match);
- result->data.resize(size);
+ result->data.resize(size);
- for (uint32_t i = 0; i < size; i++) {
- result->data.write[i].start = ovector[i * 2];
- result->data.write[i].end = ovector[i * 2 + 1];
- }
-
- pcre2_match_data_free_32(match);
- pcre2_match_context_free_32(mctx);
+ for (uint32_t i = 0; i < size; i++) {
+ result->data.write[i].start = ovector[i * 2];
+ result->data.write[i].end = ovector[i * 2 + 1];
}
+ pcre2_match_data_free_32(match);
+ pcre2_match_context_free_32(mctx);
+
result->subject = p_subject;
uint32_t count;
- const CharType *table;
+ const char32_t *table;
uint32_t entry_size;
_pattern_info(PCRE2_INFO_NAMECOUNT, &count);
@@ -304,7 +242,7 @@ Ref<RegExMatch> RegEx::search(const String &p_subject, int p_offset, int p_end)
_pattern_info(PCRE2_INFO_NAMEENTRYSIZE, &entry_size);
for (uint32_t i = 0; i < count; i++) {
- CharType id = table[i * entry_size];
+ char32_t id = table[i * entry_size];
if (result->data[id].start == -1) {
continue;
}
@@ -344,7 +282,7 @@ String RegEx::sub(const String &p_subject, const String &p_replacement, bool p_a
const int safety_zone = 1;
PCRE2_SIZE olength = p_subject.length() + 1; // space for output string and one terminating \0 character
- Vector<CharType> output;
+ Vector<char32_t> output;
output.resize(olength + safety_zone);
uint32_t flags = PCRE2_SUBSTITUTE_OVERFLOW_LENGTH;
@@ -357,55 +295,28 @@ String RegEx::sub(const String &p_subject, const String &p_replacement, bool p_a
length = p_end;
}
- if (sizeof(CharType) == 2) {
- pcre2_code_16 *c = (pcre2_code_16 *)code;
- pcre2_general_context_16 *gctx = (pcre2_general_context_16 *)general_ctx;
- pcre2_match_context_16 *mctx = pcre2_match_context_create_16(gctx);
- PCRE2_SPTR16 s = (PCRE2_SPTR16)p_subject.c_str();
- PCRE2_SPTR16 r = (PCRE2_SPTR16)p_replacement.c_str();
- PCRE2_UCHAR16 *o = (PCRE2_UCHAR16 *)output.ptrw();
+ pcre2_code_32 *c = (pcre2_code_32 *)code;
+ pcre2_general_context_32 *gctx = (pcre2_general_context_32 *)general_ctx;
+ pcre2_match_context_32 *mctx = pcre2_match_context_create_32(gctx);
+ PCRE2_SPTR32 s = (PCRE2_SPTR32)p_subject.get_data();
+ PCRE2_SPTR32 r = (PCRE2_SPTR32)p_replacement.get_data();
+ PCRE2_UCHAR32 *o = (PCRE2_UCHAR32 *)output.ptrw();
- pcre2_match_data_16 *match = pcre2_match_data_create_from_pattern_16(c, gctx);
-
- int res = pcre2_substitute_16(c, s, length, p_offset, flags, match, mctx, r, p_replacement.length(), o, &olength);
-
- if (res == PCRE2_ERROR_NOMEMORY) {
- output.resize(olength + safety_zone);
- o = (PCRE2_UCHAR16 *)output.ptrw();
- res = pcre2_substitute_16(c, s, length, p_offset, flags, match, mctx, r, p_replacement.length(), o, &olength);
- }
+ pcre2_match_data_32 *match = pcre2_match_data_create_from_pattern_32(c, gctx);
- pcre2_match_data_free_16(match);
- pcre2_match_context_free_16(mctx);
+ int res = pcre2_substitute_32(c, s, length, p_offset, flags, match, mctx, r, p_replacement.length(), o, &olength);
- if (res < 0) {
- return String();
- }
-
- } else {
- pcre2_code_32 *c = (pcre2_code_32 *)code;
- pcre2_general_context_32 *gctx = (pcre2_general_context_32 *)general_ctx;
- pcre2_match_context_32 *mctx = pcre2_match_context_create_32(gctx);
- PCRE2_SPTR32 s = (PCRE2_SPTR32)p_subject.c_str();
- PCRE2_SPTR32 r = (PCRE2_SPTR32)p_replacement.c_str();
- PCRE2_UCHAR32 *o = (PCRE2_UCHAR32 *)output.ptrw();
-
- pcre2_match_data_32 *match = pcre2_match_data_create_from_pattern_32(c, gctx);
-
- int res = pcre2_substitute_32(c, s, length, p_offset, flags, match, mctx, r, p_replacement.length(), o, &olength);
-
- if (res == PCRE2_ERROR_NOMEMORY) {
- output.resize(olength + safety_zone);
- o = (PCRE2_UCHAR32 *)output.ptrw();
- res = pcre2_substitute_32(c, s, length, p_offset, flags, match, mctx, r, p_replacement.length(), o, &olength);
- }
+ if (res == PCRE2_ERROR_NOMEMORY) {
+ output.resize(olength + safety_zone);
+ o = (PCRE2_UCHAR32 *)output.ptrw();
+ res = pcre2_substitute_32(c, s, length, p_offset, flags, match, mctx, r, p_replacement.length(), o, &olength);
+ }
- pcre2_match_data_free_32(match);
- pcre2_match_context_free_32(mctx);
+ pcre2_match_data_free_32(match);
+ pcre2_match_context_free_32(mctx);
- if (res < 0) {
- return String();
- }
+ if (res < 0) {
+ return String();
}
return String(output.ptr(), olength);
@@ -435,7 +346,7 @@ Array RegEx::get_names() const {
ERR_FAIL_COND_V(!is_valid(), result);
uint32_t count;
- const CharType *table;
+ const char32_t *table;
uint32_t entry_size;
_pattern_info(PCRE2_INFO_NAMECOUNT, &count);
@@ -453,39 +364,21 @@ Array RegEx::get_names() const {
}
RegEx::RegEx() {
- if (sizeof(CharType) == 2) {
- general_ctx = pcre2_general_context_create_16(&_regex_malloc, &_regex_free, nullptr);
-
- } else {
- general_ctx = pcre2_general_context_create_32(&_regex_malloc, &_regex_free, nullptr);
- }
+ general_ctx = pcre2_general_context_create_32(&_regex_malloc, &_regex_free, nullptr);
code = nullptr;
}
RegEx::RegEx(const String &p_pattern) {
- if (sizeof(CharType) == 2) {
- general_ctx = pcre2_general_context_create_16(&_regex_malloc, &_regex_free, nullptr);
-
- } else {
- general_ctx = pcre2_general_context_create_32(&_regex_malloc, &_regex_free, nullptr);
- }
+ general_ctx = pcre2_general_context_create_32(&_regex_malloc, &_regex_free, nullptr);
code = nullptr;
compile(p_pattern);
}
RegEx::~RegEx() {
- if (sizeof(CharType) == 2) {
- if (code) {
- pcre2_code_free_16((pcre2_code_16 *)code);
- }
- pcre2_general_context_free_16((pcre2_general_context_16 *)general_ctx);
-
- } else {
- if (code) {
- pcre2_code_free_32((pcre2_code_32 *)code);
- }
- pcre2_general_context_free_32((pcre2_general_context_32 *)general_ctx);
+ if (code) {
+ pcre2_code_free_32((pcre2_code_32 *)code);
}
+ pcre2_general_context_free_32((pcre2_general_context_32 *)general_ctx);
}
void RegEx::_bind_methods() {
diff --git a/modules/visual_script/doc_classes/VisualScript.xml b/modules/visual_script/doc_classes/VisualScript.xml
index db1ef2adc6..088d84d2ec 100644
--- a/modules/visual_script/doc_classes/VisualScript.xml
+++ b/modules/visual_script/doc_classes/VisualScript.xml
@@ -9,7 +9,7 @@
You are most likely to use this class via the Visual Script editor or when writing plugins for it.
</description>
<tutorials>
- <link>https://docs.godotengine.org/en/latest/getting_started/scripting/visual_script/index.html</link>
+ <link title="VisualScript tutorial index">https://docs.godotengine.org/en/latest/getting_started/scripting/visual_script/index.html</link>
</tutorials>
<methods>
<method name="add_custom_signal">
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
index a0dcd76d10..177f9192b8 100644
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -1060,7 +1060,7 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
} break;
case VisualScriptBuiltinFunc::TEXT_CHAR: {
- CharType result[2] = { *p_inputs[0], 0 };
+ char32_t result[2] = { *p_inputs[0], 0 };
*r_return = String(result);
diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp
index 2ac7793b8c..60a439b291 100644
--- a/modules/visual_script/visual_script_expression.cpp
+++ b/modules/visual_script/visual_script_expression.cpp
@@ -187,7 +187,7 @@ Error VisualScriptExpression::_get_token(Token &r_token) {
while (true) {
#define GET_CHAR() (str_ofs >= expression.length() ? 0 : expression[str_ofs++])
- CharType cchar = GET_CHAR();
+ char32_t cchar = GET_CHAR();
if (cchar == 0) {
r_token.type = TK_EOF;
return OK;
@@ -329,7 +329,7 @@ Error VisualScriptExpression::_get_token(Token &r_token) {
case '"': {
String str;
while (true) {
- CharType ch = GET_CHAR();
+ char32_t ch = GET_CHAR();
if (ch == 0) {
_set_error("Unterminated String");
@@ -340,13 +340,13 @@ Error VisualScriptExpression::_get_token(Token &r_token) {
} else if (ch == '\\') {
//escaped characters...
- CharType next = GET_CHAR();
+ char32_t next = GET_CHAR();
if (next == 0) {
_set_error("Unterminated String");
r_token.type = TK_ERROR;
return ERR_PARSE_ERROR;
}
- CharType res = 0;
+ char32_t res = 0;
switch (next) {
case 'b':
@@ -367,7 +367,7 @@ Error VisualScriptExpression::_get_token(Token &r_token) {
case 'u': {
// hex number
for (int j = 0; j < 4; j++) {
- CharType c = GET_CHAR();
+ char32_t c = GET_CHAR();
if (c == 0) {
_set_error("Unterminated String");
@@ -379,7 +379,7 @@ Error VisualScriptExpression::_get_token(Token &r_token) {
r_token.type = TK_ERROR;
return ERR_PARSE_ERROR;
}
- CharType v;
+ char32_t v;
if (c >= '0' && c <= '9') {
v = c - '0';
} else if (c >= 'a' && c <= 'f') {
@@ -431,7 +431,7 @@ Error VisualScriptExpression::_get_token(Token &r_token) {
#define READING_DONE 4
int reading = READING_INT;
- CharType c = cchar;
+ char32_t c = cchar;
bool exp_sign = false;
bool exp_beg = false;
bool is_float = false;
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index 87aa64211e..1b77ed3168 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -933,36 +933,36 @@ static const char *op_names[] = {
};
String VisualScriptOperator::get_caption() const {
- static const wchar_t *op_names[] = {
+ static const char32_t *op_names[] = {
//comparison
- L"A = B", //OP_EQUAL,
- L"A \u2260 B", //OP_NOT_EQUAL,
- L"A < B", //OP_LESS,
- L"A \u2264 B", //OP_LESS_EQUAL,
- L"A > B", //OP_GREATER,
- L"A \u2265 B", //OP_GREATER_EQUAL,
+ U"A = B", //OP_EQUAL,
+ U"A \u2260 B", //OP_NOT_EQUAL,
+ U"A < B", //OP_LESS,
+ U"A \u2264 B", //OP_LESS_EQUAL,
+ U"A > B", //OP_GREATER,
+ U"A \u2265 B", //OP_GREATER_EQUAL,
//mathematic
- L"A + B", //OP_ADD,
- L"A - B", //OP_SUBTRACT,
- L"A \u00D7 B", //OP_MULTIPLY,
- L"A \u00F7 B", //OP_DIVIDE,
- L"\u00AC A", //OP_NEGATE,
- L"+ A", //OP_POSITIVE,
- L"A mod B", //OP_MODULE,
- L"A .. B", //OP_STRING_CONCAT,
+ U"A + B", //OP_ADD,
+ U"A - B", //OP_SUBTRACT,
+ U"A \u00D7 B", //OP_MULTIPLY,
+ U"A \u00F7 B", //OP_DIVIDE,
+ U"\u00AC A", //OP_NEGATE,
+ U"+ A", //OP_POSITIVE,
+ U"A mod B", //OP_MODULE,
+ U"A .. B", //OP_STRING_CONCAT,
//bitwise
- L"A << B", //OP_SHIFT_LEFT,
- L"A >> B", //OP_SHIFT_RIGHT,
- L"A & B", //OP_BIT_AND,
- L"A | B", //OP_BIT_OR,
- L"A ^ B", //OP_BIT_XOR,
- L"~A", //OP_BIT_NEGATE,
+ U"A << B", //OP_SHIFT_LEFT,
+ U"A >> B", //OP_SHIFT_RIGHT,
+ U"A & B", //OP_BIT_AND,
+ U"A | B", //OP_BIT_OR,
+ U"A ^ B", //OP_BIT_XOR,
+ U"~A", //OP_BIT_NEGATE,
//logic
- L"A and B", //OP_AND,
- L"A or B", //OP_OR,
- L"A xor B", //OP_XOR,
- L"not A", //OP_NOT,
- L"A in B", //OP_IN,
+ U"A and B", //OP_AND,
+ U"A or B", //OP_OR,
+ U"A xor B", //OP_XOR,
+ U"not A", //OP_NOT,
+ U"A in B", //OP_IN,
};
return op_names[op];
diff --git a/modules/webrtc/webrtc_data_channel_gdnative.h b/modules/webrtc/webrtc_data_channel_gdnative.h
index b578802250..03396d207d 100644
--- a/modules/webrtc/webrtc_data_channel_gdnative.h
+++ b/modules/webrtc/webrtc_data_channel_gdnative.h
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef WEBRTC_GDNATIVE_ENABLED
-
#ifndef WEBRTC_DATA_CHANNEL_GDNATIVE_H
#define WEBRTC_DATA_CHANNEL_GDNATIVE_H
+#ifdef WEBRTC_GDNATIVE_ENABLED
+
#include "modules/gdnative/include/net/godot_net.h"
#include "webrtc_data_channel.h"
@@ -75,6 +75,6 @@ public:
~WebRTCDataChannelGDNative();
};
-#endif // WEBRTC_DATA_CHANNEL_GDNATIVE_H
-
#endif // WEBRTC_GDNATIVE_ENABLED
+
+#endif // WEBRTC_DATA_CHANNEL_GDNATIVE_H
diff --git a/modules/webrtc/webrtc_data_channel_js.h b/modules/webrtc/webrtc_data_channel_js.h
index 455866cbf1..7545910e66 100644
--- a/modules/webrtc/webrtc_data_channel_js.h
+++ b/modules/webrtc/webrtc_data_channel_js.h
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef JAVASCRIPT_ENABLED
-
#ifndef WEBRTC_DATA_CHANNEL_JS_H
#define WEBRTC_DATA_CHANNEL_JS_H
+#ifdef JAVASCRIPT_ENABLED
+
#include "webrtc_data_channel.h"
class WebRTCDataChannelJS : public WebRTCDataChannel {
@@ -88,6 +88,6 @@ public:
~WebRTCDataChannelJS();
};
-#endif // WEBRTC_DATA_CHANNEL_JS_H
-
#endif // JAVASCRIPT_ENABLED
+
+#endif // WEBRTC_DATA_CHANNEL_JS_H
diff --git a/modules/webrtc/webrtc_multiplayer.h b/modules/webrtc/webrtc_multiplayer.h
index bfdcf6daa1..fb37bd7722 100644
--- a/modules/webrtc/webrtc_multiplayer.h
+++ b/modules/webrtc/webrtc_multiplayer.h
@@ -112,4 +112,4 @@ public:
ConnectionStatus get_connection_status() const override;
};
-#endif
+#endif // WEBRTC_MULTIPLAYER_H
diff --git a/modules/webrtc/webrtc_peer_connection_gdnative.h b/modules/webrtc/webrtc_peer_connection_gdnative.h
index 74b7db1307..846b65c466 100644
--- a/modules/webrtc/webrtc_peer_connection_gdnative.h
+++ b/modules/webrtc/webrtc_peer_connection_gdnative.h
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef WEBRTC_GDNATIVE_ENABLED
-
#ifndef WEBRTC_PEER_CONNECTION_GDNATIVE_H
#define WEBRTC_PEER_CONNECTION_GDNATIVE_H
+#ifdef WEBRTC_GDNATIVE_ENABLED
+
#include "modules/gdnative/include/net/godot_net.h"
#include "webrtc_peer_connection.h"
@@ -68,6 +68,6 @@ public:
~WebRTCPeerConnectionGDNative();
};
-#endif // WEBRTC_PEER_CONNECTION_GDNATIVE_H
-
#endif // WEBRTC_GDNATIVE_ENABLED
+
+#endif // WEBRTC_PEER_CONNECTION_GDNATIVE_H
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index 95b778caf6..e318b35495 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -453,7 +453,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
String name;
bool first = true;
for (int i = 0; i < basename.length(); i++) {
- CharType c = basename[i];
+ char32_t c = basename[i];
if (c >= '0' && c <= '9' && first) {
continue;
}
@@ -484,7 +484,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
int segments = 0;
bool first = true;
for (int i = 0; i < pname.length(); i++) {
- CharType c = pname[i];
+ char32_t c = pname[i];
if (first && c == '.') {
if (r_error) {
*r_error = TTR("Package segments must be of non-zero length.");
@@ -873,7 +873,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
if (string_flags & UTF8_FLAG) {
} else {
uint32_t len = decode_uint16(&p_manifest[string_at]);
- Vector<CharType> ucstring;
+ Vector<char32_t> ucstring;
ucstring.resize(len + 1);
for (uint32_t j = 0; j < len; j++) {
uint16_t c = decode_uint16(&p_manifest[string_at + 2 + 2 * j]);
@@ -1334,7 +1334,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
} else {
String str;
for (uint32_t i = 0; i < len; i++) {
- CharType c = decode_uint16(&p_bytes[offset + i * 2]);
+ char32_t c = decode_uint16(&p_bytes[offset + i * 2]);
if (c == 0) {
break;
}
diff --git a/platform/android/java/lib/res/values/dimens.xml b/platform/android/java/lib/res/values/dimens.xml
new file mode 100644
index 0000000000..9034dbbcc1
--- /dev/null
+++ b/platform/android/java/lib/res/values/dimens.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <dimen name="text_edit_height">48dp</dimen>
+</resources>
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
index 35852f31ef..524f32bf5e 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -56,6 +56,8 @@ import android.content.SharedPreferences.Editor;
import android.content.pm.ConfigurationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
@@ -75,6 +77,7 @@ import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
+import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
@@ -148,8 +151,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
private void setButtonPausedState(boolean paused) {
mStatePaused = paused;
- int stringResourceID = paused ? R.string.text_button_resume :
- R.string.text_button_pause;
+ int stringResourceID = paused ? R.string.text_button_resume : R.string.text_button_pause;
mPauseButton.setText(stringResourceID);
}
@@ -160,8 +162,6 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
public GodotRenderView mRenderView;
private boolean godot_initialized = false;
- private GodotEditText mEditText;
-
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private Sensor mGravity;
@@ -218,6 +218,13 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
containerLayout = new FrameLayout(activity);
containerLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+ // GodotEditText layout
+ GodotEditText editText = new GodotEditText(activity);
+ editText.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT,
+ (int)getResources().getDimension(R.dimen.text_edit_height)));
+ // ...add to FrameLayout
+ containerLayout.addView(editText);
+
GodotLib.setup(command_line);
final String videoDriver = GodotLib.getGlobal("rendering/quality/driver/driver_name");
@@ -230,9 +237,21 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
View view = mRenderView.getView();
containerLayout.addView(view, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+ editText.setView(mRenderView);
+ io.setEdit(editText);
- mEditText = new GodotEditText(activity, mRenderView);
- io.setEdit(mEditText);
+ view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ Point fullSize = new Point();
+ activity.getWindowManager().getDefaultDisplay().getSize(fullSize);
+ Rect gameSize = new Rect();
+ mRenderView.getView().getWindowVisibleDisplayFrame(gameSize);
+
+ final int keyboardHeight = fullSize.y - gameSize.bottom;
+ GodotLib.setVirtualKeyboardHeight(keyboardHeight);
+ }
+ });
mRenderView.queueOnRenderThread(new Runnable() {
@Override
@@ -448,7 +467,6 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
final Activity activity = getActivity();
Window window = activity.getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
- window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
mClipboard = (ClipboardManager)activity.getSystemService(Context.CLIPBOARD_SERVICE);
pluginRegistry = GodotPluginRegistry.initializePluginRegistry(this);
@@ -585,21 +603,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
}
@Override
- public void onStart() {
- super.onStart();
-
- mRenderView.getView().post(new Runnable() {
- @Override
- public void run() {
- mEditText.onInitView();
- }
- });
- }
-
- @Override
public void onDestroy() {
- mEditText.onDestroyView();
-
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
plugin.onMainDestroy();
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
index 6855f91f1c..c95339c583 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
@@ -32,27 +32,16 @@ package org.godotengine.godot.input;
import org.godotengine.godot.*;
-import android.app.Activity;
import android.content.Context;
-import android.graphics.Point;
-import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.text.InputFilter;
import android.text.InputType;
import android.util.AttributeSet;
-import android.view.Gravity;
import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.view.ViewTreeObserver;
-import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
-import android.widget.FrameLayout;
-import android.widget.PopupWindow;
import java.lang.ref.WeakReference;
@@ -67,8 +56,6 @@ public class GodotEditText extends EditText {
// Fields
// ===========================================================
private GodotRenderView mRenderView;
- private View mKeyboardView;
- private PopupWindow mKeyboardWindow;
private GodotTextInputWrapper mInputWrapper;
private EditHandler sHandler = new EditHandler(this);
private String mOriginText;
@@ -93,52 +80,24 @@ public class GodotEditText extends EditText {
// ===========================================================
// Constructors
// ===========================================================
- public GodotEditText(final Context context, final GodotRenderView view) {
+ public GodotEditText(final Context context) {
super(context);
+ initView();
+ }
- setPadding(0, 0, 0, 0);
- setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_DONE);
- setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
-
- mRenderView = view;
- mInputWrapper = new GodotTextInputWrapper(mRenderView, this);
- setOnEditorActionListener(mInputWrapper);
- view.getView().requestFocus();
-
- // Create a popup window with an invisible layout for the virtual keyboard,
- // so the view can be resized to get the vk height without resizing the main godot view.
- final FrameLayout keyboardLayout = new FrameLayout(context);
- keyboardLayout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
- keyboardLayout.setVisibility(View.INVISIBLE);
- keyboardLayout.addView(this);
- mKeyboardView = keyboardLayout;
-
- mKeyboardWindow = new PopupWindow(keyboardLayout, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
- mKeyboardWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
- mKeyboardWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
- mKeyboardWindow.setFocusable(true); // for the text edit to work
- mKeyboardWindow.setTouchable(false); // inputs need to go through
-
- keyboardLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- Point fullSize = new Point();
- ((Activity)mRenderView.getView().getContext()).getWindowManager().getDefaultDisplay().getSize(fullSize);
- Rect gameSize = new Rect();
- mKeyboardWindow.getContentView().getWindowVisibleDisplayFrame(gameSize);
-
- final int keyboardHeight = fullSize.y - gameSize.bottom;
- GodotLib.setVirtualKeyboardHeight(keyboardHeight);
- }
- });
+ public GodotEditText(final Context context, final AttributeSet attrs) {
+ super(context, attrs);
+ initView();
}
- public void onInitView() {
- mKeyboardWindow.showAtLocation(mRenderView.getView(), Gravity.NO_GRAVITY, 0, 0);
+ public GodotEditText(final Context context, final AttributeSet attrs, final int defStyle) {
+ super(context, attrs, defStyle);
+ initView();
}
- public void onDestroyView() {
- mKeyboardWindow.dismiss();
+ protected void initView() {
+ setPadding(0, 0, 0, 0);
+ setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_DONE);
}
public boolean isMultiline() {
@@ -170,7 +129,7 @@ public class GodotEditText extends EditText {
edit.mInputWrapper.setOriginText(text);
edit.addTextChangedListener(edit.mInputWrapper);
- final InputMethodManager imm = (InputMethodManager)mKeyboardView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ final InputMethodManager imm = (InputMethodManager)mRenderView.getView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(edit, 0);
}
} break;
@@ -179,7 +138,7 @@ public class GodotEditText extends EditText {
GodotEditText edit = (GodotEditText)msg.obj;
edit.removeTextChangedListener(mInputWrapper);
- final InputMethodManager imm = (InputMethodManager)mKeyboardView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ final InputMethodManager imm = (InputMethodManager)mRenderView.getView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(edit.getWindowToken(), 0);
edit.mRenderView.getView().requestFocus();
} break;
@@ -193,6 +152,17 @@ public class GodotEditText extends EditText {
}
// ===========================================================
+ // Getter & Setter
+ // ===========================================================
+ public void setView(final GodotRenderView view) {
+ mRenderView = view;
+ if (mInputWrapper == null)
+ mInputWrapper = new GodotTextInputWrapper(mRenderView, this);
+ setOnEditorActionListener(mInputWrapper);
+ view.getView().requestFocus();
+ }
+
+ // ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
@Override
diff --git a/platform/iphone/display_server_iphone.mm b/platform/iphone/display_server_iphone.mm
index 1721da3db6..eea87cecc9 100644
--- a/platform/iphone/display_server_iphone.mm
+++ b/platform/iphone/display_server_iphone.mm
@@ -701,7 +701,7 @@ Error DisplayServerIPhone::native_video_play(String p_path, float p_volume, Stri
if (p_path.begins_with("res://")) {
if (PackedData::get_singleton()->has_path(p_path)) {
- printf("Unable to play %S using the native player as it resides in a .pck file\n", p_path.c_str());
+ printf("Unable to play %s using the native player as it resides in a .pck file\n", p_path.utf8().get_data());
return ERR_INVALID_PARAMETER;
} else {
p_path = p_path.replace("res:/", ProjectSettings::get_singleton()->get_resource_path());
@@ -712,7 +712,7 @@ Error DisplayServerIPhone::native_video_play(String p_path, float p_volume, Stri
memdelete(f);
- printf("Playing video: %S\n", p_path.c_str());
+ printf("Playing video: %s\n", p_path.utf8().get_data());
String file_path = ProjectSettings::get_singleton()->globalize_path(p_path);
diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp
index a889717f20..97f954ebb2 100644
--- a/platform/iphone/export/export.cpp
+++ b/platform/iphone/export/export.cpp
@@ -115,7 +115,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
}
for (int i = 0; i < pname.length(); i++) {
- CharType c = pname[i];
+ char32_t c = pname[i];
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '.')) {
if (r_error) {
*r_error = vformat(TTR("The character '%s' is not allowed in Identifier."), String::chr(c));
diff --git a/platform/iphone/in_app_store.mm b/platform/iphone/in_app_store.mm
index dfec5d7634..1477f92200 100644
--- a/platform/iphone/in_app_store.mm
+++ b/platform/iphone/in_app_store.mm
@@ -138,7 +138,7 @@ Error InAppStore::request_product_info(Dictionary p_params) {
NSMutableArray *array = [[[NSMutableArray alloc] initWithCapacity:pids.size()] autorelease];
for (int i = 0; i < pids.size(); i++) {
- printf("******** adding %ls to product list\n", pids[i].c_str());
+ printf("******** adding %s to product list\n", pids[i].utf8().get_data());
NSString *pid = [[[NSString alloc] initWithUTF8String:pids[i].utf8().get_data()] autorelease];
[array addObject:pid];
};
diff --git a/platform/iphone/ios.mm b/platform/iphone/ios.mm
index ad26d0ada3..6d7699c0c9 100644
--- a/platform/iphone/ios.mm
+++ b/platform/iphone/ios.mm
@@ -86,7 +86,7 @@ String iOS::get_rate_url(int p_app_id) const {
// ios7 for everything?
ret = templ_iOS7.replace("APP_ID", String::num(p_app_id));
- printf("returning rate url %ls\n", ret.c_str());
+ printf("returning rate url %s\n", ret.utf8().get_data());
return ret;
};
diff --git a/platform/iphone/os_iphone.mm b/platform/iphone/os_iphone.mm
index d1a69642b1..946fd51923 100644
--- a/platform/iphone/os_iphone.mm
+++ b/platform/iphone/os_iphone.mm
@@ -278,7 +278,7 @@ Error OSIPhone::shell_open(String p_uri) {
return ERR_CANT_OPEN;
}
- printf("opening url %ls\n", p_uri.c_str());
+ printf("opening url %s\n", p_uri.utf8().get_data());
// if (@available(iOS 10, *)) {
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
@@ -293,7 +293,7 @@ void OSIPhone::set_user_data_dir(String p_dir) {
DirAccess *da = DirAccess::open(p_dir);
user_data_dir = da->get_current_dir();
- printf("setting data dir to %ls from %ls\n", user_data_dir.c_str(), p_dir.c_str());
+ printf("setting data dir to %s from %s\n", user_data_dir.utf8().get_data(), p_dir.utf8().get_data());
memdelete(da);
}
diff --git a/platform/linuxbsd/crash_handler_linuxbsd.cpp b/platform/linuxbsd/crash_handler_linuxbsd.cpp
index b3553e961a..e2b88b7704 100644
--- a/platform/linuxbsd/crash_handler_linuxbsd.cpp
+++ b/platform/linuxbsd/crash_handler_linuxbsd.cpp
@@ -67,7 +67,7 @@ static void handle_crash(int sig) {
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH);
}
- fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str());
+ fprintf(stderr, "Dumping the backtrace. %s\n", msg.utf8().get_data());
char **strings = backtrace_symbols(bt_buffer, size);
if (strings) {
for (size_t i = 1; i < size; i++) {
@@ -109,7 +109,7 @@ static void handle_crash(int sig) {
output.erase(output.length() - 1, 1);
}
- fprintf(stderr, "[%ld] %s (%ls)\n", (long int)i, fname, output.c_str());
+ fprintf(stderr, "[%ld] %s (%s)\n", (long int)i, fname, output.utf8().get_data());
}
free(strings);
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index a0aced26ab..fe9e253cc9 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -83,6 +83,13 @@
#define VALUATOR_TILTX 3
#define VALUATOR_TILTY 4
+//#define DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED
+#ifdef DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED
+#define DEBUG_LOG_X11(...) printf(__VA_ARGS__)
+#else
+#define DEBUG_LOG_X11(...)
+#endif
+
static const double abs_resolution_mult = 10000.0;
static const double abs_resolution_range_mult = 10.0;
@@ -681,6 +688,14 @@ DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, u
return id;
}
+void DisplayServerX11::show_window(WindowID p_id) {
+ _THREAD_SAFE_METHOD_
+
+ WindowData &wd = windows[p_id];
+
+ XMapWindow(x11_display, wd.x11_window);
+}
+
void DisplayServerX11::delete_sub_window(WindowID p_id) {
_THREAD_SAFE_METHOD_
@@ -689,6 +704,8 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) {
WindowData &wd = windows[p_id];
+ DEBUG_LOG_X11("delete_sub_window: %lu (%u) \n", wd.x11_window, p_id);
+
while (wd.transient_children.size()) {
window_set_transient(wd.transient_children.front()->get(), INVALID_WINDOW_ID);
}
@@ -725,15 +742,31 @@ ObjectID DisplayServerX11::window_get_attached_instance_id(WindowID p_window) co
}
DisplayServerX11::WindowID DisplayServerX11::get_window_at_screen_position(const Point2i &p_position) const {
-#warning This is an incorrect implementation, if windows overlap, it should return the topmost visible one or none if occluded by a foreign window
-
+ WindowID found_window = INVALID_WINDOW_ID;
+ WindowID parent_window = INVALID_WINDOW_ID;
+ unsigned int focus_order = 0;
for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
- Rect2i win_rect = Rect2i(window_get_position(E->key()), window_get_size(E->key()));
+ const WindowData &wd = E->get();
+
+ // Discard windows with no focus.
+ if (wd.focus_order == 0) {
+ continue;
+ }
+
+ // Find topmost window which contains the given position.
+ WindowID window_id = E->key();
+ Rect2i win_rect = Rect2i(window_get_position(window_id), window_get_size(window_id));
if (win_rect.has_point(p_position)) {
- return E->key();
+ // For siblings, pick the window which was focused last.
+ if ((parent_window != wd.transient_parent) || (wd.focus_order > focus_order)) {
+ found_window = window_id;
+ parent_window = wd.transient_parent;
+ focus_order = wd.focus_order;
+ }
}
}
- return INVALID_WINDOW_ID;
+
+ return found_window;
}
void DisplayServerX11::window_set_title(const String &p_title, WindowID p_window) {
@@ -842,24 +875,34 @@ void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent
ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd_window = windows[p_window];
- ERR_FAIL_COND(wd_window.transient_parent == p_parent);
+ WindowID prev_parent = wd_window.transient_parent;
+ ERR_FAIL_COND(prev_parent == p_parent);
ERR_FAIL_COND_MSG(wd_window.on_top, "Windows with the 'on top' can't become transient.");
if (p_parent == INVALID_WINDOW_ID) {
//remove transient
- ERR_FAIL_COND(wd_window.transient_parent == INVALID_WINDOW_ID);
- ERR_FAIL_COND(!windows.has(wd_window.transient_parent));
+ ERR_FAIL_COND(prev_parent == INVALID_WINDOW_ID);
+ ERR_FAIL_COND(!windows.has(prev_parent));
- WindowData &wd_parent = windows[wd_window.transient_parent];
+ WindowData &wd_parent = windows[prev_parent];
wd_window.transient_parent = INVALID_WINDOW_ID;
wd_parent.transient_children.erase(p_window);
XSetTransientForHint(x11_display, wd_window.x11_window, None);
+
+ // Set focus to parent sub window to avoid losing all focus with nested menus.
+ // RevertToPointerRoot is used to make sure we don't lose all focus in case
+ // a subwindow and its parent are both destroyed.
+ if (wd_window.menu_type && !wd_window.no_focus) {
+ if (!wd_parent.no_focus) {
+ XSetInputFocus(x11_display, wd_parent.x11_window, RevertToPointerRoot, CurrentTime);
+ }
+ }
} else {
ERR_FAIL_COND(!windows.has(p_parent));
- ERR_FAIL_COND_MSG(wd_window.transient_parent != INVALID_WINDOW_ID, "Window already has a transient parent");
+ ERR_FAIL_COND_MSG(prev_parent != INVALID_WINDOW_ID, "Window already has a transient parent");
WindowData &wd_parent = windows[p_parent];
wd_window.transient_parent = p_parent;
@@ -2285,6 +2328,11 @@ void DisplayServerX11::_send_window_event(const WindowData &wd, WindowEvent p_ev
void DisplayServerX11::process_events() {
_THREAD_SAFE_METHOD_
+#ifdef DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED
+ static int frame = 0;
+ ++frame;
+#endif
+
if (app_focused) {
//verify that one of the windows has focus, else send focus out notification
bool focus_found = false;
@@ -2301,6 +2349,7 @@ void DisplayServerX11::process_events() {
if (delta > 250) {
//X11 can go between windows and have no focus for a while, when creating them or something else. Use this as safety to avoid unnecessary focus in/outs.
if (OS::get_singleton()->get_main_loop()) {
+ DEBUG_LOG_X11("All focus lost, triggering NOTIFICATION_APPLICATION_FOCUS_OUT\n");
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
}
app_focused = false;
@@ -2323,6 +2372,10 @@ void DisplayServerX11::process_events() {
XEvent event;
XNextEvent(x11_display, &event);
+ if (XFilterEvent(&event, None)) {
+ continue;
+ }
+
WindowID window_id = MAIN_WINDOW_ID;
// Assign the event to the relevant window
@@ -2333,10 +2386,6 @@ void DisplayServerX11::process_events() {
}
}
- if (XFilterEvent(&event, None)) {
- continue;
- }
-
if (XGetEventData(x11_display, &event.xcookie)) {
if (event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) {
XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data;
@@ -2499,32 +2548,67 @@ void DisplayServerX11::process_events() {
XFreeEventData(x11_display, &event.xcookie);
switch (event.type) {
- case Expose:
+ case MapNotify: {
+ DEBUG_LOG_X11("[%u] MapNotify window=%lu (%u) \n", frame, event.xmap.window, window_id);
+
+ const WindowData &wd = windows[window_id];
+
+ // Set focus when menu window is started.
+ // RevertToPointerRoot is used to make sure we don't lose all focus in case
+ // a subwindow and its parent are both destroyed.
+ if (wd.menu_type && !wd.no_focus) {
+ XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
+ }
+ } break;
+
+ case Expose: {
+ DEBUG_LOG_X11("[%u] Expose window=%lu (%u), count='%u' \n", frame, event.xexpose.window, window_id, event.xexpose.count);
+
Main::force_redraw();
- break;
+ } break;
+
+ case NoExpose: {
+ DEBUG_LOG_X11("[%u] NoExpose drawable=%lu (%u) \n", frame, event.xnoexpose.drawable, window_id);
- case NoExpose:
windows[window_id].minimized = true;
- break;
+ } break;
case VisibilityNotify: {
+ DEBUG_LOG_X11("[%u] VisibilityNotify window=%lu (%u), state=%u \n", frame, event.xvisibility.window, window_id, event.xvisibility.state);
+
XVisibilityEvent *visibility = (XVisibilityEvent *)&event;
windows[window_id].minimized = (visibility->state == VisibilityFullyObscured);
} break;
+
case LeaveNotify: {
+ DEBUG_LOG_X11("[%u] LeaveNotify window=%lu (%u), mode='%u' \n", frame, event.xcrossing.window, window_id, event.xcrossing.mode);
+
if (!mouse_mode_grab) {
_send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT);
}
} break;
+
case EnterNotify: {
+ DEBUG_LOG_X11("[%u] EnterNotify window=%lu (%u), mode='%u' \n", frame, event.xcrossing.window, window_id, event.xcrossing.mode);
+
if (!mouse_mode_grab) {
_send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
}
} break;
- case FocusIn:
- windows[window_id].focused = true;
- _send_window_event(windows[window_id], WINDOW_EVENT_FOCUS_IN);
+
+ case FocusIn: {
+ DEBUG_LOG_X11("[%u] FocusIn window=%lu (%u), mode='%u' \n", frame, event.xfocus.window, window_id, event.xfocus.mode);
+
+ WindowData &wd = windows[window_id];
+
+ wd.focused = true;
+
+ // Keep track of focus order for overlapping windows.
+ static unsigned int focus_order = 0;
+ wd.focus_order = ++focus_order;
+
+ _send_window_event(wd, WINDOW_EVENT_FOCUS_IN);
if (mouse_mode_grab) {
// Show and update the cursor if confined and the window regained focus.
@@ -2548,8 +2632,8 @@ void DisplayServerX11::process_events() {
XIGrabDevice(x11_display, xi.touch_devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &xi.touch_event_mask);
}*/
#endif
- if (windows[window_id].xic) {
- XSetICFocus(windows[window_id].xic);
+ if (wd.xic) {
+ XSetICFocus(wd.xic);
}
if (!app_focused) {
@@ -2558,12 +2642,17 @@ void DisplayServerX11::process_events() {
}
app_focused = true;
}
- break;
+ } break;
+
+ case FocusOut: {
+ DEBUG_LOG_X11("[%u] FocusOut window=%lu (%u), mode='%u' \n", frame, event.xfocus.window, window_id, event.xfocus.mode);
+
+ WindowData &wd = windows[window_id];
+
+ wd.focused = false;
- case FocusOut:
- windows[window_id].focused = false;
Input::get_singleton()->release_pressed_events();
- _send_window_event(windows[window_id], WINDOW_EVENT_FOCUS_OUT);
+ _send_window_event(wd, WINDOW_EVENT_FOCUS_OUT);
if (mouse_mode_grab) {
for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
@@ -2592,14 +2681,26 @@ void DisplayServerX11::process_events() {
}
xi.state.clear();
#endif
- if (windows[window_id].xic) {
- XSetICFocus(windows[window_id].xic);
+ if (wd.xic) {
+ XSetICFocus(wd.xic);
+ }
+ } break;
+
+ case ConfigureNotify: {
+ DEBUG_LOG_X11("[%u] ConfigureNotify window=%lu (%u), event=%lu, above=%lu, override_redirect=%u \n", frame, event.xconfigure.window, window_id, event.xconfigure.event, event.xconfigure.above, event.xconfigure.override_redirect);
+
+ const WindowData &wd = windows[window_id];
+
+ // Set focus when menu window is re-used.
+ // RevertToPointerRoot is used to make sure we don't lose all focus in case
+ // a subwindow and its parent are both destroyed.
+ if (wd.menu_type && !wd.no_focus) {
+ XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
}
- break;
- case ConfigureNotify:
_window_changed(&event);
- break;
+ } break;
+
case ButtonPress:
case ButtonRelease: {
/* exit in case of a mouse button press */
@@ -2626,7 +2727,18 @@ void DisplayServerX11::process_events() {
mb->set_pressed((event.type == ButtonPress));
+ const WindowData &wd = windows[window_id];
+
if (event.type == ButtonPress) {
+ DEBUG_LOG_X11("[%u] ButtonPress window=%lu (%u), button_index=%u \n", frame, event.xbutton.window, window_id, mb->get_button_index());
+
+ // Ensure window focus on click.
+ // RevertToPointerRoot is used to make sure we don't lose all focus in case
+ // a subwindow and its parent are both destroyed.
+ if (!wd.no_focus) {
+ XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
+ }
+
uint64_t diff = OS::get_singleton()->get_ticks_usec() / 1000 - last_click_ms;
if (mb->get_button_index() == last_click_button_index) {
@@ -2645,6 +2757,33 @@ void DisplayServerX11::process_events() {
last_click_ms += diff;
last_click_pos = Point2i(event.xbutton.x, event.xbutton.y);
}
+ } else {
+ DEBUG_LOG_X11("[%u] ButtonRelease window=%lu (%u), button_index=%u \n", frame, event.xbutton.window, window_id, mb->get_button_index());
+
+ if (!wd.focused) {
+ // Propagate the event to the focused window,
+ // because it's received only on the topmost window.
+ // Note: This is needed for drag & drop to work between windows,
+ // because the engine expects events to keep being processed
+ // on the same window dragging started.
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ const WindowData &wd_other = E->get();
+ WindowID window_id_other = E->key();
+ if (wd_other.focused) {
+ if (window_id_other != window_id) {
+ int x, y;
+ Window child;
+ XTranslateCoordinates(x11_display, wd.x11_window, wd_other.x11_window, event.xbutton.x, event.xbutton.y, &x, &y, &child);
+
+ mb->set_window_id(window_id_other);
+ mb->set_position(Vector2(x, y));
+ mb->set_global_position(mb->get_position());
+ Input::get_singleton()->accumulate_input_event(mb);
+ }
+ break;
+ }
+ }
+ }
}
Input::get_singleton()->accumulate_input_event(mb);
@@ -2694,6 +2833,9 @@ void DisplayServerX11::process_events() {
break;
}
+ const WindowData &wd = windows[window_id];
+ bool focused = wd.focused;
+
if (mouse_mode == MOUSE_MODE_CAPTURED) {
if (xi.relative_motion.x == 0 && xi.relative_motion.y == 0) {
break;
@@ -2702,7 +2844,7 @@ void DisplayServerX11::process_events() {
Point2i new_center = pos;
pos = last_mouse_pos + xi.relative_motion;
center = new_center;
- do_mouse_warp = windows[window_id].focused; // warp the cursor if we're focused in
+ do_mouse_warp = focused; // warp the cursor if we're focused in
}
if (!last_mouse_pos_valid) {
@@ -2744,14 +2886,11 @@ void DisplayServerX11::process_events() {
}
mm->set_tilt(xi.tilt);
- // Make the absolute position integral so it doesn't look _too_ weird :)
- Point2i posi(pos);
-
_get_key_modifier_state(event.xmotion.state, mm);
mm->set_button_mask(mouse_get_button_state());
- mm->set_position(posi);
- mm->set_global_position(posi);
- Input::get_singleton()->set_mouse_position(posi);
+ mm->set_position(pos);
+ mm->set_global_position(pos);
+ Input::get_singleton()->set_mouse_position(pos);
mm->set_speed(Input::get_singleton()->get_last_mouse_speed());
mm->set_relative(rel);
@@ -2762,8 +2901,32 @@ void DisplayServerX11::process_events() {
// Don't propagate the motion event unless we have focus
// this is so that the relative motion doesn't get messed up
// after we regain focus.
- if (windows[window_id].focused || !mouse_mode_grab) {
+ if (focused) {
Input::get_singleton()->accumulate_input_event(mm);
+ } else {
+ // Propagate the event to the focused window,
+ // because it's received only on the topmost window.
+ // Note: This is needed for drag & drop to work between windows,
+ // because the engine expects events to keep being processed
+ // on the same window dragging started.
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ const WindowData &wd_other = E->get();
+ if (wd_other.focused) {
+ int x, y;
+ Window child;
+ XTranslateCoordinates(x11_display, wd.x11_window, wd_other.x11_window, event.xmotion.x, event.xmotion.y, &x, &y, &child);
+
+ Point2i pos_focused(x, y);
+
+ mm->set_window_id(E->key());
+ mm->set_position(pos_focused);
+ mm->set_global_position(pos_focused);
+ mm->set_speed(Input::get_singleton()->get_last_mouse_speed());
+ Input::get_singleton()->accumulate_input_event(mm);
+
+ break;
+ }
+ }
}
} break;
@@ -3140,12 +3303,37 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask;
- WindowID id;
+ WindowID id = window_id_counter++;
+ WindowData &wd = windows[id];
+
+ if ((id != MAIN_WINDOW_ID) && (p_flags & WINDOW_FLAG_BORDERLESS_BIT)) {
+ wd.menu_type = true;
+ }
+
+ if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) {
+ wd.menu_type = true;
+ wd.no_focus = true;
+ }
+
+ // Setup for menu subwindows:
+ // - override_redirect forces the WM not to interfere with the window, to avoid delays due to
+ // handling decorations and placement.
+ // On the other hand, focus changes need to be handled manually when this is set.
+ // - save_under is a hint for the WM to keep the content of windows behind to avoid repaint.
+ if (wd.menu_type) {
+ windowAttributes.override_redirect = True;
+ windowAttributes.save_under = True;
+ valuemask |= CWOverrideRedirect | CWSaveUnder;
+ }
+
{
- WindowData wd;
wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo->screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo->depth, InputOutput, visualInfo->visual, valuemask, &windowAttributes);
- XMapWindow(x11_display, wd.x11_window);
+ // Enable receiving notification when the window is initialized (MapNotify)
+ // so the focus can be set at the right time.
+ if (wd.menu_type && !wd.no_focus) {
+ XSelectInput(x11_display, wd.x11_window, StructureNotifyMask);
+ }
//associate PID
// make PID known to X11
@@ -3221,58 +3409,26 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
_update_context(wd);
- id = window_id_counter++;
-
- windows[id] = wd;
-
- {
- bool make_utility = false;
-
- if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) {
- Hints hints;
- Atom property;
- hints.flags = 2;
- hints.decorations = 0;
- property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
- XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
-
- make_utility = true;
- }
- if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) {
- make_utility = true;
- }
-
- if (make_utility) {
- //this one seems to disable the fade animations for regular windows
- //but has the drawback that will not get focus by default, so
- //we need to force it, unless no focus requested
-
- Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_UTILITY", False);
- Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False);
-
- XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1);
-
- if (!(p_flags & WINDOW_FLAG_NO_FOCUS_BIT)) {
- //but as utility appears unfocused, it needs to be forcefuly focused, unless no focus requested
- XEvent xev;
- Atom net_active_window = XInternAtom(x11_display, "_NET_ACTIVE_WINDOW", False);
+ if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) {
+ Hints hints;
+ Atom property;
+ hints.flags = 2;
+ hints.decorations = 0;
+ property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
+ XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
+ }
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = wd.x11_window;
- xev.xclient.message_type = net_active_window;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = 1;
- xev.xclient.data.l[1] = CurrentTime;
+ if (wd.menu_type) {
+ // Set Utility type to disable fade animations.
+ Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_UTILITY", False);
+ Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False);
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
- }
- } else {
- Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
- Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False);
+ XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1);
+ } else {
+ Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
+ Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False);
- XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1);
- }
+ XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1);
}
_update_size_hints(id);
@@ -3293,8 +3449,6 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
XFree(visualInfo);
}
- WindowData &wd = windows[id];
-
window_set_mode(p_mode, id);
//sync size
@@ -3316,6 +3470,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u
if (cursors[current_cursor] != None) {
XDefineCursor(x11_display, wd.x11_window, cursors[current_cursor]);
}
+
return id;
}
@@ -3555,6 +3710,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
window_set_flag(WindowFlags(i), true, main_window);
}
}
+ show_window(main_window);
//create RenderingDevice if used
#if defined(VULKAN_ENABLED)
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index fb50b484a0..57cee910a0 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -132,6 +132,9 @@ class DisplayServerX11 : public DisplayServer {
ObjectID instance_id;
+ bool menu_type = false;
+ bool no_focus = false;
+
//better to guess on the fly, given WM can change it
//WindowMode mode;
bool fullscreen = false; //OS can't exit from this mode
@@ -141,6 +144,8 @@ class DisplayServerX11 : public DisplayServer {
Vector2i last_position_before_fs;
bool focused = false;
bool minimized = false;
+
+ unsigned int focus_order = 0;
};
Map<WindowID, WindowData> windows;
@@ -277,6 +282,7 @@ public:
virtual Vector<DisplayServer::WindowID> get_window_list() const;
virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
+ virtual void show_window(WindowID p_id);
virtual void delete_sub_window(WindowID p_id);
virtual WindowID get_window_at_screen_position(const Point2i &p_position) const;
diff --git a/platform/osx/crash_handler_osx.mm b/platform/osx/crash_handler_osx.mm
index 5da0118686..9fb2f63935 100644
--- a/platform/osx/crash_handler_osx.mm
+++ b/platform/osx/crash_handler_osx.mm
@@ -90,7 +90,7 @@ static void handle_crash(int sig) {
if (OS::get_singleton()->get_main_loop())
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH);
- fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str());
+ fprintf(stderr, "Dumping the backtrace. %s\n", msg.utf8().get_data());
char **strings = backtrace_symbols(bt_buffer, size);
if (strings) {
void *load_addr = (void *)load_address();
@@ -142,7 +142,7 @@ static void handle_crash(int sig) {
}
}
- fprintf(stderr, "[%zu] %ls\n", i, output.c_str());
+ fprintf(stderr, "[%zu] %s\n", i, output.utf8().get_data());
}
free(strings);
diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h
index 68e8454fd0..d8f3f81ff6 100644
--- a/platform/osx/display_server_osx.h
+++ b/platform/osx/display_server_osx.h
@@ -230,6 +230,7 @@ public:
virtual Vector<int> get_window_list() const override;
virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override;
+ virtual void show_window(WindowID p_id) override;
virtual void delete_sub_window(WindowID p_id) override;
virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index 1676e0d425..adfb47324e 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -2314,18 +2314,23 @@ DisplayServer::WindowID DisplayServerOSX::create_sub_window(WindowMode p_mode, u
_THREAD_SAFE_METHOD_
WindowID id = _create_window(p_mode, p_rect);
- WindowData &wd = windows[id];
for (int i = 0; i < WINDOW_FLAG_MAX; i++) {
if (p_flags & (1 << i)) {
window_set_flag(WindowFlags(i), true, id);
}
}
+
+ return id;
+}
+
+void DisplayServerOSX::show_window(WindowID p_id) {
+ WindowData &wd = windows[p_id];
+
if (wd.no_focus) {
[wd.window_object orderFront:nil];
} else {
[wd.window_object makeKeyAndOrderFront:nil];
}
- return id;
}
void DisplayServerOSX::_send_window_event(const WindowData &wd, WindowEvent p_event) {
@@ -3774,7 +3779,7 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode
window_set_flag(WindowFlags(i), true, main_window);
}
}
- [windows[main_window].window_object makeKeyAndOrderFront:nil];
+ show_window(MAIN_WINDOW_ID);
#if defined(OPENGL_ENABLED)
if (rendering_driver == "opengl_es") {
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index 0cf02ef69b..9f2160dd9e 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -78,7 +78,7 @@ class EditorExportPlatformOSX : public EditorExportPlatform {
}
for (int i = 0; i < pname.length(); i++) {
- CharType c = pname[i];
+ char32_t c = pname[i];
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '.')) {
if (r_error) {
*r_error = vformat(TTR("The character '%s' is not allowed in Identifier."), String::chr(c));
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 401ba6c35d..44ab075816 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -296,7 +296,7 @@ Error OS_UWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
void OS_UWP::set_clipboard(const String &p_text) {
DataPackage ^ clip = ref new DataPackage();
clip->RequestedOperation = DataPackageOperation::Copy;
- clip->SetText(ref new Platform::String((const wchar_t *)p_text.c_str()));
+ clip->SetText(ref new Platform::String((LPCWSTR)(p_text.utf16().get_data())));
Clipboard::SetContent(clip);
};
@@ -346,8 +346,8 @@ void OS_UWP::finalize_core() {
}
void OS_UWP::alert(const String &p_alert, const String &p_title) {
- Platform::String ^ alert = ref new Platform::String(p_alert.c_str());
- Platform::String ^ title = ref new Platform::String(p_title.c_str());
+ Platform::String ^ alert = ref new Platform::String((LPCWSTR)(p_alert.utf16().get_data()));
+ Platform::String ^ title = ref new Platform::String((LPCWSTR)(p_title.utf16().get_data()));
MessageDialog ^ msg = ref new MessageDialog(alert, title);
@@ -738,7 +738,7 @@ static String format_error_message(DWORD id) {
Error OS_UWP::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
String full_path = "game/" + p_path;
- p_library_handle = (void *)LoadPackagedLibrary(full_path.c_str(), 0);
+ p_library_handle = (void *)LoadPackagedLibrary((LPCWSTR)(full_path.utf16().get_data()), 0);
ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + full_path + ", error: " + format_error_message(GetLastError()) + ".");
return OK;
}
diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp
index 996d9722f5..02031ef6bb 100644
--- a/platform/windows/crash_handler_windows.cpp
+++ b/platform/windows/crash_handler_windows.cpp
@@ -175,7 +175,7 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
msg = proj_settings->get("debug/settings/crash_handler/message");
}
- fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str());
+ fprintf(stderr, "Dumping the backtrace. %s\n", msg.utf8().get_data());
int n = 0;
do {
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index a9f25fa078..4e1da22bb0 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -65,6 +65,7 @@ def get_opts():
# Vista support dropped after EOL due to GH-10243
("target_win_version", "Targeted Windows version, >= 0x0601 (Windows 7)", "0x0601"),
EnumVariable("debug_symbols", "Add debugging symbols to release builds", "yes", ("yes", "no", "full")),
+ EnumVariable("windows_subsystem", "Windows subsystem", "gui", ("console", "gui")),
BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False),
("msvc_version", "MSVC version to use. Ignored if VCINSTALLDIR is set in shell env.", None),
BoolVariable("use_mingw", "Use the Mingw compiler, even if MSVC is installed. Only used on Windows.", False),
@@ -177,6 +178,8 @@ def configure_msvc(env, manual_msvc_config):
"""Configure env to work with MSVC"""
# Build type
+ if env["tests"]:
+ env["windows_subsystem"] = "console"
if env["target"] == "release":
if env["optimize"] == "speed": # optimize for speed (default)
@@ -199,12 +202,15 @@ def configure_msvc(env, manual_msvc_config):
env.AppendUnique(CPPDEFINES=["DEBUG_ENABLED"])
env.Append(LINKFLAGS=["/DEBUG"])
- env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"])
-
if env["debug_symbols"] == "full" or env["debug_symbols"] == "yes":
env.AppendUnique(CCFLAGS=["/Z7"])
env.AppendUnique(LINKFLAGS=["/DEBUG"])
+ if env["windows_subsystem"] == "gui":
+ env.Append(LINKFLAGS=["/SUBSYSTEM:WINDOWS"])
+ else:
+ env.Append(LINKFLAGS=["/SUBSYSTEM:CONSOLE"])
+
## Compile/link flags
env.AppendUnique(CCFLAGS=["/MT", "/Gd", "/GR", "/nologo"])
@@ -302,6 +308,9 @@ def configure_mingw(env):
## Build type
+ if env["tests"]:
+ env["windows_subsystem"] = "console"
+
if env["target"] == "release":
env.Append(CCFLAGS=["-msse2"])
@@ -334,7 +343,10 @@ def configure_mingw(env):
env.Append(CCFLAGS=["-g3"])
env.Append(CPPDEFINES=["DEBUG_ENABLED"])
- env.Append(LINKFLAGS=["-Wl,--subsystem,windows"])
+ if env["windows_subsystem"] == "gui":
+ env.Append(LINKFLAGS=["-Wl,--subsystem,windows"])
+ else:
+ env.Append(LINKFLAGS=["-Wl,--subsystem,console"])
## Compiler configuration
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 9469e35536..7f4669b3b2 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -42,7 +42,7 @@ static String format_error_message(DWORD id) {
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr);
- String msg = "Error " + itos(id) + ": " + String(messageBuffer, size);
+ String msg = "Error " + itos(id) + ": " + String::utf16((const char16_t *)messageBuffer, size);
LocalFree(messageBuffer);
@@ -78,7 +78,7 @@ String DisplayServerWindows::get_name() const {
}
void DisplayServerWindows::alert(const String &p_alert, const String &p_title) {
- MessageBoxW(nullptr, p_alert.c_str(), p_title.c_str(), MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
+ MessageBoxW(nullptr, (LPCWSTR)(p_alert.utf16().get_data()), (LPCWSTR)(p_title.utf16().get_data()), MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
}
void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) {
@@ -177,11 +177,12 @@ void DisplayServerWindows::clipboard_set(const String &p_text) {
}
EmptyClipboard();
- HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (text.length() + 1) * sizeof(CharType));
+ Char16String utf16 = text.utf16();
+ HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (utf16.length() + 1) * sizeof(WCHAR));
ERR_FAIL_COND_MSG(mem == nullptr, "Unable to allocate memory for clipboard contents.");
LPWSTR lptstrCopy = (LPWSTR)GlobalLock(mem);
- memcpy(lptstrCopy, text.c_str(), (text.length() + 1) * sizeof(CharType));
+ memcpy(lptstrCopy, utf16.get_data(), (utf16.length() + 1) * sizeof(WCHAR));
GlobalUnlock(mem);
SetClipboardData(CF_UNICODETEXT, mem);
@@ -218,7 +219,7 @@ String DisplayServerWindows::clipboard_get() const {
if (mem != nullptr) {
LPWSTR ptr = (LPWSTR)GlobalLock(mem);
if (ptr != nullptr) {
- ret = String((CharType *)ptr);
+ ret = String::utf16((const char16_t *)ptr);
GlobalUnlock(mem);
};
};
@@ -493,15 +494,21 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod
wd.no_focus = true;
}
- _update_window_style(window_id);
+ return window_id;
+}
- ShowWindow(wd.hWnd, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) ? SW_SHOWNOACTIVATE : SW_SHOW); // Show The Window
- if (!(p_flags & WINDOW_FLAG_NO_FOCUS_BIT)) {
+void DisplayServerWindows::show_window(WindowID p_id) {
+ WindowData &wd = windows[p_id];
+
+ if (p_id != MAIN_WINDOW_ID) {
+ _update_window_style(p_id);
+ }
+
+ ShowWindow(wd.hWnd, wd.no_focus ? SW_SHOWNOACTIVATE : SW_SHOW); // Show The Window
+ if (!wd.no_focus) {
SetForegroundWindow(wd.hWnd); // Slightly Higher Priority
SetFocus(wd.hWnd); // Sets Keyboard Focus To
}
-
- return window_id;
}
void DisplayServerWindows::delete_sub_window(WindowID p_window) {
@@ -587,7 +594,7 @@ void DisplayServerWindows::window_set_title(const String &p_title, WindowID p_wi
_THREAD_SAFE_METHOD_
ERR_FAIL_COND(!windows.has(p_window));
- SetWindowTextW(windows[p_window].hWnd, p_title.c_str());
+ SetWindowTextW(windows[p_window].hWnd, (LPCWSTR)(p_title.utf16().get_data()));
}
int DisplayServerWindows::window_get_current_screen(WindowID p_window) const {
@@ -1131,17 +1138,10 @@ void DisplayServerWindows::window_set_ime_position(const Point2i &p_pos, WindowI
void DisplayServerWindows::console_set_visible(bool p_enabled) {
_THREAD_SAFE_METHOD_
- if (console_visible == p_enabled) {
+ if (console_visible == p_enabled)
return;
- }
- if (p_enabled && GetConsoleWindow() == nullptr) { // Open new console if not attached.
- own_console = true;
- AllocConsole();
- }
- if (own_console) { // Note: Do not hide parent console.
- ShowWindow(GetConsoleWindow(), p_enabled ? SW_SHOW : SW_HIDE);
- console_visible = p_enabled;
- }
+ ShowWindow(GetConsoleWindow(), p_enabled ? SW_SHOW : SW_HIDE);
+ console_visible = p_enabled;
}
bool DisplayServerWindows::is_console_visible() const {
@@ -1424,13 +1424,13 @@ String DisplayServerWindows::keyboard_get_layout_language(int p_index) const {
HKL *layouts = (HKL *)memalloc(layout_count * sizeof(HKL));
GetKeyboardLayoutList(layout_count, layouts);
- wchar_t buf[LOCALE_NAME_MAX_LENGTH];
- memset(buf, 0, LOCALE_NAME_MAX_LENGTH * sizeof(wchar_t));
+ WCHAR buf[LOCALE_NAME_MAX_LENGTH];
+ memset(buf, 0, LOCALE_NAME_MAX_LENGTH * sizeof(WCHAR));
LCIDToLocaleName(MAKELCID(LOWORD(layouts[p_index]), SORT_DEFAULT), buf, LOCALE_NAME_MAX_LENGTH, 0);
memfree(layouts);
- return String(buf).substr(0, 2);
+ return String::utf16((const char16_t *)buf).substr(0, 2);
}
String _get_full_layout_name_from_registry(HKL p_layout) {
@@ -1438,17 +1438,17 @@ String _get_full_layout_name_from_registry(HKL p_layout) {
String ret;
HKEY hkey;
- wchar_t layout_text[1024];
- memset(layout_text, 0, 1024 * sizeof(wchar_t));
+ WCHAR layout_text[1024];
+ memset(layout_text, 0, 1024 * sizeof(WCHAR));
- if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, (LPCWSTR)id.c_str(), 0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS) {
+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, (LPCWSTR)(id.utf16().get_data()), 0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS) {
return ret;
}
DWORD buffer = 1024;
DWORD vtype = REG_SZ;
if (RegQueryValueExW(hkey, L"Layout Text", NULL, &vtype, (LPBYTE)layout_text, &buffer) == ERROR_SUCCESS) {
- ret = String(layout_text);
+ ret = String::utf16((const char16_t *)layout_text);
}
RegCloseKey(hkey);
return ret;
@@ -1464,15 +1464,15 @@ String DisplayServerWindows::keyboard_get_layout_name(int p_index) const {
String ret = _get_full_layout_name_from_registry(layouts[p_index]); // Try reading full name from Windows registry, fallback to locale name if failed (e.g. on Wine).
if (ret == String()) {
- wchar_t buf[LOCALE_NAME_MAX_LENGTH];
- memset(buf, 0, LOCALE_NAME_MAX_LENGTH * sizeof(wchar_t));
+ WCHAR buf[LOCALE_NAME_MAX_LENGTH];
+ memset(buf, 0, LOCALE_NAME_MAX_LENGTH * sizeof(WCHAR));
LCIDToLocaleName(MAKELCID(LOWORD(layouts[p_index]), SORT_DEFAULT), buf, LOCALE_NAME_MAX_LENGTH, 0);
- wchar_t name[1024];
- memset(name, 0, 1024 * sizeof(wchar_t));
+ WCHAR name[1024];
+ memset(name, 0, 1024 * sizeof(WCHAR));
GetLocaleInfoEx(buf, LOCALE_SLOCALIZEDDISPLAYNAME, (LPWSTR)&name, 1024);
- ret = String(name);
+ ret = String::utf16((const char16_t *)name);
}
memfree(layouts);
@@ -2712,7 +2712,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
case WM_DROPFILES: {
HDROP hDropInfo = (HDROP)wParam;
const int buffsize = 4096;
- wchar_t buf[buffsize];
+ WCHAR buf[buffsize];
int fcount = DragQueryFileW(hDropInfo, 0xFFFFFFFF, nullptr, 0);
@@ -2720,7 +2720,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
for (int i = 0; i < fcount; i++) {
DragQueryFileW(hDropInfo, i, buf, buffsize);
- String file = buf;
+ String file = String::utf16((const char16_t *)buf);
files.push_back(file);
}
@@ -3022,18 +3022,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
shift_mem = false;
control_mem = false;
meta_mem = false;
-
- if (AttachConsole(ATTACH_PARENT_PROCESS)) {
- FILE *_file = nullptr;
- freopen_s(&_file, "CONOUT$", "w", stdout);
- freopen_s(&_file, "CONOUT$", "w", stderr);
- freopen_s(&_file, "CONIN$", "r", stdin);
-
- printf("\n");
- console_visible = true;
- } else {
- console_visible = false;
- }
+ console_visible = IsWindowVisible(GetConsoleWindow());
hInstance = ((OS_Windows *)OS::get_singleton())->get_hinstance();
pressrc = 0;
@@ -3139,9 +3128,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
}
}
- ShowWindow(windows[MAIN_WINDOW_ID].hWnd, SW_SHOW); // Show The Window
- SetForegroundWindow(windows[MAIN_WINDOW_ID].hWnd); // Slightly Higher Priority
- SetFocus(windows[MAIN_WINDOW_ID].hWnd); // Sets Keyboard Focus To
+ show_window(MAIN_WINDOW_ID);
#if defined(VULKAN_ENABLED)
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 0ad8cd3d07..7bd93a7086 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -405,7 +405,6 @@ private:
bool drop_events = false;
bool in_dispatch_input_event = false;
bool console_visible = false;
- bool own_console = false;
WNDCLASSEXW wc;
@@ -461,6 +460,7 @@ public:
virtual Vector<DisplayServer::WindowID> get_window_list() const;
virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
+ virtual void show_window(WindowID p_window);
virtual void delete_sub_window(WindowID p_window);
virtual WindowID get_window_at_screen_position(const Point2i &p_position) const;
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 5b15896b0c..f73516b370 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -84,7 +84,7 @@ static String format_error_message(DWORD id) {
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr);
- String msg = "Error " + itos(id) + ": " + String(messageBuffer, size);
+ String msg = "Error " + itos(id) + ": " + String::utf16((const char16_t *)messageBuffer, size);
LocalFree(messageBuffer);
@@ -107,15 +107,11 @@ void RedirectIOToConsole() {
// set the screen buffer to be big enough to let us scroll text
- GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),
-
- &coninfo);
+ GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
coninfo.dwSize.Y = MAX_CONSOLE_LINES;
- SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),
-
- coninfo.dwSize);
+ SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
// redirect unbuffered STDOUT to the console
@@ -265,10 +261,10 @@ Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_han
DLL_DIRECTORY_COOKIE cookie = nullptr;
if (p_also_set_library_path && has_dll_directory_api) {
- cookie = add_dll_directory(path.get_base_dir().c_str());
+ cookie = add_dll_directory((LPCWSTR)(path.get_base_dir().utf16().get_data()));
}
- p_library_handle = (void *)LoadLibraryExW(path.c_str(), nullptr, (p_also_set_library_path && has_dll_directory_api) ? LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0);
+ p_library_handle = (void *)LoadLibraryExW((LPCWSTR)(path.utf16().get_data()), nullptr, (p_also_set_library_path && has_dll_directory_api) ? LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0);
ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + format_error_message(GetLastError()) + ".");
if (cookie) {
@@ -407,7 +403,7 @@ uint64_t OS_Windows::get_ticks_usec() const {
String OS_Windows::_quote_command_line_argument(const String &p_text) const {
for (int i = 0; i < p_text.size(); i++) {
- CharType c = p_text[i];
+ char32_t c = p_text[i];
if (c == ' ' || c == '&' || c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}' || c == '^' || c == '=' || c == ';' || c == '!' || c == '\'' || c == '+' || c == ',' || c == '`' || c == '~') {
return "\"" + p_text + "\"";
}
@@ -428,7 +424,7 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
// Note: _wpopen is calling command as "cmd.exe /c argss", instead of executing it directly, add extra quotes around full command, to prevent it from stripping quotes in the command.
argss = _quote_command_line_argument(argss);
- FILE *f = _wpopen(argss.c_str(), L"r");
+ FILE *f = _wpopen((LPCWSTR)(argss.utf16().get_data()), L"r");
ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
char buf[65535];
@@ -463,13 +459,8 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments,
ZeroMemory(&pi.pi, sizeof(pi.pi));
LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si;
- Vector<CharType> modstr; // Windows wants to change this no idea why.
- modstr.resize(cmdline.size());
- for (int i = 0; i < cmdline.size(); i++) {
- modstr.write[i] = cmdline[i];
- }
-
- int ret = CreateProcessW(nullptr, modstr.ptrw(), nullptr, nullptr, 0, NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW, nullptr, nullptr, si_w, &pi.pi);
+ Char16String modstr = cmdline.utf16(); // Windows wants to change this no idea why.
+ int ret = CreateProcessW(nullptr, (LPWSTR)(modstr.ptrw()), nullptr, nullptr, 0, NORMAL_PRIORITY_CLASS & CREATE_NO_WINDOW, nullptr, nullptr, si_w, &pi.pi);
ERR_FAIL_COND_V(ret == 0, ERR_CANT_FORK);
if (p_blocking) {
@@ -509,26 +500,26 @@ int OS_Windows::get_process_id() const {
}
Error OS_Windows::set_cwd(const String &p_cwd) {
- if (_wchdir(p_cwd.c_str()) != 0)
+ if (_wchdir((LPCWSTR)(p_cwd.utf16().get_data())) != 0)
return ERR_CANT_OPEN;
return OK;
}
String OS_Windows::get_executable_path() const {
- wchar_t bufname[4096];
+ WCHAR bufname[4096];
GetModuleFileNameW(nullptr, bufname, 4096);
- String s = bufname;
+ String s = String::utf16((const char16_t *)bufname);
return s;
}
bool OS_Windows::has_environment(const String &p_var) const {
#ifdef MINGW_ENABLED
- return _wgetenv(p_var.c_str()) != nullptr;
+ return _wgetenv((LPCWSTR)(p_var.utf16().get_data())) != nullptr;
#else
- wchar_t *env;
+ WCHAR *env;
size_t len;
- _wdupenv_s(&env, &len, p_var.c_str());
+ _wdupenv_s(&env, &len, (LPCWSTR)(p_var.utf16().get_data()));
const bool has_env = env != nullptr;
free(env);
return has_env;
@@ -536,16 +527,16 @@ bool OS_Windows::has_environment(const String &p_var) const {
};
String OS_Windows::get_environment(const String &p_var) const {
- wchar_t wval[0x7Fff]; // MSDN says 32767 char is the maximum
- int wlen = GetEnvironmentVariableW(p_var.c_str(), wval, 0x7Fff);
+ WCHAR wval[0x7fff]; // MSDN says 32767 char is the maximum
+ int wlen = GetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), wval, 0x7fff);
if (wlen > 0) {
- return wval;
+ return String::utf16((const char16_t *)wval);
}
return "";
}
bool OS_Windows::set_environment(const String &p_var, const String &p_value) const {
- return (bool)SetEnvironmentVariableW(p_var.c_str(), p_value.c_str());
+ return (bool)SetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), (LPCWSTR)(p_value.utf16().get_data()));
}
String OS_Windows::get_stdin_string(bool p_block) {
@@ -558,7 +549,7 @@ String OS_Windows::get_stdin_string(bool p_block) {
}
Error OS_Windows::shell_open(String p_uri) {
- ShellExecuteW(nullptr, nullptr, p_uri.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ ShellExecuteW(nullptr, nullptr, (LPCWSTR)(p_uri.utf16().get_data()), nullptr, nullptr, SW_SHOWNORMAL);
return OK;
}
@@ -701,7 +692,7 @@ String OS_Windows::get_system_dir(SystemDir p_dir) const {
PWSTR szPath;
HRESULT res = SHGetKnownFolderPath(id, 0, nullptr, &szPath);
ERR_FAIL_COND_V(res != S_OK, String());
- String path = String(szPath);
+ String path = String::utf16((const char16_t *)szPath);
CoTaskMemFree(szPath);
return path;
}
@@ -727,7 +718,7 @@ String OS_Windows::get_user_data_dir() const {
String OS_Windows::get_unique_id() const {
HW_PROFILE_INFO HwProfInfo;
ERR_FAIL_COND_V(!GetCurrentHwProfile(&HwProfInfo), "");
- return String(HwProfInfo.szHwProfileGuid);
+ return String::utf16((const char16_t *)(HwProfInfo.szHwProfileGuid), HW_PROFILE_GUIDLEN);
}
bool OS_Windows::_check_internal_feature_support(const String &p_feature) {
@@ -744,9 +735,11 @@ bool OS_Windows::is_disable_crash_handler() const {
Error OS_Windows::move_to_trash(const String &p_path) {
SHFILEOPSTRUCTW sf;
- WCHAR *from = new WCHAR[p_path.length() + 2];
- wcscpy_s(from, p_path.length() + 1, p_path.c_str());
- from[p_path.length() + 1] = 0;
+
+ Char16String utf16 = p_path.utf16();
+ WCHAR *from = new WCHAR[utf16.length() + 2];
+ wcscpy_s(from, utf16.length() + 1, (LPCWSTR)(utf16.get_data()));
+ from[utf16.length() + 1] = 0;
sf.hwnd = main_window;
sf.wFunc = FO_DELETE;
diff --git a/platform_methods.py b/platform_methods.py
index ec394d76d8..be4957475d 100644
--- a/platform_methods.py
+++ b/platform_methods.py
@@ -55,7 +55,7 @@ def run_in_subprocess(builder_function):
finally:
try:
os.remove(json_path)
- except (OSError, IOError) as e:
+ except OSError as e:
# Do not fail the entire build if it cannot delete a temporary file
print(
"WARNING: Could not delete temporary file: path=%r; [%s] %s" % (json_path, e.__class__.__name__, e)
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index 68e99445d8..fd4d5981ff 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -56,7 +56,7 @@ void Camera2D::_update_scroll() {
viewport->set_canvas_transform(xform);
- Size2 screen_size = viewport->get_visible_rect().size;
+ Size2 screen_size = _get_camera_screen_size();
Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5) : Point2());
get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, group_name, "_camera_moved", xform, screen_offset);
@@ -94,7 +94,7 @@ Transform2D Camera2D::get_camera_transform() {
ERR_FAIL_COND_V(custom_viewport && !ObjectDB::get_instance(custom_viewport_id), Transform2D());
- Size2 screen_size = viewport->get_visible_rect().size;
+ Size2 screen_size = _get_camera_screen_size();
Point2 new_camera_pos = get_global_transform().get_origin();
Point2 ret_camera_pos;
@@ -274,7 +274,7 @@ void Camera2D::_notification(int p_what) {
}
Transform2D inv_camera_transform = get_camera_transform().affine_inverse();
- Size2 screen_size = get_viewport_rect().size;
+ Size2 screen_size = _get_camera_screen_size();
Vector2 screen_endpoints[4] = {
inv_camera_transform.xform(Vector2(0, 0)),
@@ -321,7 +321,7 @@ void Camera2D::_notification(int p_what) {
}
Transform2D inv_camera_transform = get_camera_transform().affine_inverse();
- Size2 screen_size = get_viewport_rect().size;
+ Size2 screen_size = _get_camera_screen_size();
Vector2 margin_endpoints[4] = {
inv_camera_transform.xform(Vector2((screen_size.width / 2) - ((screen_size.width / 2) * drag_margin[MARGIN_LEFT]), (screen_size.height / 2) - ((screen_size.height / 2) * drag_margin[MARGIN_TOP]))),
@@ -469,7 +469,7 @@ void Camera2D::reset_smoothing() {
void Camera2D::align() {
ERR_FAIL_COND(custom_viewport && !ObjectDB::get_instance(custom_viewport_id));
- Size2 screen_size = viewport->get_visible_rect().size;
+ Size2 screen_size = _get_camera_screen_size();
Point2 current_camera_pos = get_global_transform().get_origin();
if (anchor_mode == ANCHOR_MODE_DRAG_CENTER) {
@@ -507,6 +507,14 @@ Point2 Camera2D::get_camera_screen_center() const {
return camera_screen_center;
}
+Size2 Camera2D::_get_camera_screen_size() const {
+ // special case if the camera2D is in the root viewport
+ if (Engine::get_singleton()->is_editor_hint() && get_viewport()->get_parent_viewport() == get_tree()->get_root()) {
+ return Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height"));
+ }
+ return get_viewport_rect().size;
+}
+
void Camera2D::set_h_drag_enabled(bool p_enabled) {
h_drag_enabled = p_enabled;
}
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h
index 0a4e269c40..867a5562b2 100644
--- a/scene/2d/camera_2d.h
+++ b/scene/2d/camera_2d.h
@@ -94,6 +94,8 @@ protected:
Camera2DProcessMode process_mode;
+ Size2 _get_camera_screen_size() const;
+
protected:
virtual Transform2D get_camera_transform();
void _notification(int p_what);
diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp
index 7e07019578..d1be93e55d 100644
--- a/scene/2d/sprite_2d.cpp
+++ b/scene/2d/sprite_2d.cpp
@@ -498,8 +498,8 @@ void Sprite2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v");
ADD_GROUP("Animation", "");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp
index 56367e9bdd..e7f3f53ca9 100644
--- a/scene/3d/collision_shape_3d.cpp
+++ b/scene/3d/collision_shape_3d.cpp
@@ -44,23 +44,36 @@
//TODO: Implement CylinderShape and HeightMapShape?
-void CollisionShape3D::make_convex_from_brothers() {
+void CollisionShape3D::make_convex_from_siblings() {
Node *p = get_parent();
if (!p) {
return;
}
+ Vector<Vector3> vertices;
+
for (int i = 0; i < p->get_child_count(); i++) {
Node *n = p->get_child(i);
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(n);
if (mi) {
Ref<Mesh> m = mi->get_mesh();
if (m.is_valid()) {
- Ref<Shape3D> s = m->create_convex_shape();
- set_shape(s);
+ for (int j = 0; j < m->get_surface_count(); j++) {
+ Array a = m->surface_get_arrays(j);
+ if (!a.empty()) {
+ Vector<Vector3> v = a[RenderingServer::ARRAY_VERTEX];
+ for (int k = 0; k < v.size(); k++) {
+ vertices.append(mi->get_transform().xform(v[k]));
+ }
+ }
+ }
}
}
}
+
+ Ref<ConvexPolygonShape3D> shape = memnew(ConvexPolygonShape3D);
+ shape->set_points(vertices);
+ set_shape(shape);
}
void CollisionShape3D::_update_in_shape_owner(bool p_xform_only) {
@@ -137,8 +150,8 @@ 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_brothers"), &CollisionShape3D::make_convex_from_brothers);
- ClassDB::set_method_flags("CollisionShape3D", "make_convex_from_brothers", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
+ 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);
ClassDB::bind_method(D_METHOD("_update_debug_shape"), &CollisionShape3D::_update_debug_shape);
diff --git a/scene/3d/collision_shape_3d.h b/scene/3d/collision_shape_3d.h
index a32a3efeb6..35f40d27b1 100644
--- a/scene/3d/collision_shape_3d.h
+++ b/scene/3d/collision_shape_3d.h
@@ -60,7 +60,7 @@ protected:
static void _bind_methods();
public:
- void make_convex_from_brothers();
+ void make_convex_from_siblings();
void set_shape(const Ref<Shape3D> &p_shape);
Ref<Shape3D> get_shape() const;
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index c4480e3ed2..6fa0fc6ecb 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -301,6 +301,36 @@ void GPUParticles3D::_validate_property(PropertyInfo &property) const {
}
}
+void GPUParticles3D::emit_particle(const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
+ RS::get_singleton()->particles_emit(particles, p_transform, p_velocity, p_color, p_custom, p_emit_flags);
+}
+
+void GPUParticles3D::_attach_sub_emitter() {
+ Node *n = get_node_or_null(sub_emitter);
+ if (n) {
+ GPUParticles3D *sen = Object::cast_to<GPUParticles3D>(n);
+ if (sen && sen != this) {
+ RS::get_singleton()->particles_set_subemitter(particles, sen->particles);
+ }
+ }
+}
+
+void GPUParticles3D::set_sub_emitter(const NodePath &p_path) {
+ if (is_inside_tree()) {
+ RS::get_singleton()->particles_set_subemitter(particles, RID());
+ }
+
+ sub_emitter = p_path;
+
+ if (is_inside_tree() && sub_emitter != NodePath()) {
+ _attach_sub_emitter();
+ }
+}
+
+NodePath GPUParticles3D::get_sub_emitter() const {
+ return sub_emitter;
+}
+
void GPUParticles3D::_notification(int p_what) {
if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) {
if (can_process()) {
@@ -319,6 +349,16 @@ void GPUParticles3D::_notification(int p_what) {
}
}
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ if (sub_emitter != NodePath()) {
+ _attach_sub_emitter();
+ }
+ }
+
+ if (p_what == NOTIFICATION_EXIT_TREE) {
+ RS::get_singleton()->particles_set_subemitter(particles, RID());
+ }
+
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
// make sure particles are updated before rendering occurs if they were active before
if (is_visible_in_tree() && !RS::get_singleton()->particles_is_inactive(particles)) {
@@ -369,8 +409,14 @@ void GPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("restart"), &GPUParticles3D::restart);
ClassDB::bind_method(D_METHOD("capture_aabb"), &GPUParticles3D::capture_aabb);
+ ClassDB::bind_method(D_METHOD("set_sub_emitter", "path"), &GPUParticles3D::set_sub_emitter);
+ ClassDB::bind_method(D_METHOD("get_sub_emitter"), &GPUParticles3D::get_sub_emitter);
+
+ ClassDB::bind_method(D_METHOD("emit_particle", "xform", "velocity", "color", "custom", "flags"), &GPUParticles3D::emit_particle);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "sub_emitter", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GPUParticles3D"), "set_sub_emitter", "get_sub_emitter");
ADD_GROUP("Time", "");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
@@ -396,6 +442,12 @@ void GPUParticles3D::_bind_methods() {
BIND_ENUM_CONSTANT(DRAW_ORDER_LIFETIME);
BIND_ENUM_CONSTANT(DRAW_ORDER_VIEW_DEPTH);
+ BIND_ENUM_CONSTANT(EMIT_FLAG_POSITION);
+ BIND_ENUM_CONSTANT(EMIT_FLAG_ROTATION_SCALE);
+ BIND_ENUM_CONSTANT(EMIT_FLAG_VELOCITY);
+ BIND_ENUM_CONSTANT(EMIT_FLAG_COLOR);
+ BIND_ENUM_CONSTANT(EMIT_FLAG_CUSTOM);
+
BIND_CONSTANT(MAX_DRAW_PASSES);
}
diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h
index e04473727d..0d8dadd31d 100644
--- a/scene/3d/gpu_particles_3d.h
+++ b/scene/3d/gpu_particles_3d.h
@@ -64,6 +64,7 @@ private:
bool local_coords;
int fixed_fps;
bool fractional_delta;
+ NodePath sub_emitter;
Ref<Material> process_material;
@@ -71,6 +72,8 @@ private:
Vector<Ref<Mesh>> draw_passes;
+ void _attach_sub_emitter();
+
protected:
static void _bind_methods();
void _notification(int p_what);
@@ -121,13 +124,27 @@ public:
virtual String get_configuration_warning() const override;
+ void set_sub_emitter(const NodePath &p_path);
+ NodePath get_sub_emitter() const;
+
void restart();
+ enum EmitFlags {
+ EMIT_FLAG_POSITION = RS::PARTICLES_EMIT_FLAG_POSITION,
+ EMIT_FLAG_ROTATION_SCALE = RS::PARTICLES_EMIT_FLAG_ROTATION_SCALE,
+ EMIT_FLAG_VELOCITY = RS::PARTICLES_EMIT_FLAG_VELOCITY,
+ EMIT_FLAG_COLOR = RS::PARTICLES_EMIT_FLAG_COLOR,
+ EMIT_FLAG_CUSTOM = RS::PARTICLES_EMIT_FLAG_CUSTOM
+ };
+
+ void emit_particle(const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags);
+
AABB capture_aabb() const;
GPUParticles3D();
~GPUParticles3D();
};
VARIANT_ENUM_CAST(GPUParticles3D::DrawOrder)
+VARIANT_ENUM_CAST(GPUParticles3D::EmitFlags)
#endif // PARTICLES_H
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index a267c57f5e..d3d7cdc1ce 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -106,7 +106,7 @@ SoftBody3D::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) {
offset = obj_tocopy.offset;
}
-SoftBody3D::PinnedPoint SoftBody3D::PinnedPoint::operator=(const PinnedPoint &obj) {
+SoftBody3D::PinnedPoint &SoftBody3D::PinnedPoint::operator=(const PinnedPoint &obj) {
point_index = obj.point_index;
spatial_attachment_path = obj.spatial_attachment_path;
spatial_attachment = obj.spatial_attachment;
diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_body_3d.h
index 85cfb81637..c59a0b3aa3 100644
--- a/scene/3d/soft_body_3d.h
+++ b/scene/3d/soft_body_3d.h
@@ -74,7 +74,7 @@ public:
PinnedPoint();
PinnedPoint(const PinnedPoint &obj_tocopy);
- PinnedPoint operator=(const PinnedPoint &obj);
+ PinnedPoint &operator=(const PinnedPoint &obj);
};
private:
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 3b76cb6499..6e38196ba6 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -667,8 +667,8 @@ void Sprite3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
ADD_GROUP("Animation", "");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
ADD_GROUP("Region", "region_");
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index 6fef44481a..aaae03df68 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -60,7 +60,7 @@ void BaseButton::_gui_input(Ref<InputEvent> p_event) {
Ref<InputEventMouseButton> mouse_button = p_event;
bool ui_accept = p_event->is_action("ui_accept") && !p_event->is_echo();
- bool button_masked = mouse_button.is_valid() && ((1 << (mouse_button->get_button_index() - 1)) & button_mask) > 0;
+ bool button_masked = mouse_button.is_valid() && ((1 << (mouse_button->get_button_index() - 1)) & button_mask) != 0;
if (button_masked || ui_accept) {
on_action_event(p_event);
return;
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index f49acc1b96..9e3418a5c9 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -188,7 +188,7 @@ void Label::_notification(int p_what) {
int spaces = 0;
while (to && to->char_pos >= 0) {
taken += to->pixel_width;
- if (to != from && to->space_count) {
+ if (to->space_count) {
spaces += to->space_count;
}
to = to->next;
@@ -235,8 +235,8 @@ void Label::_notification(int p_what) {
float x_ofs_shadow = x_ofs;
for (int i = 0; i < from->word_len; i++) {
if (visible_chars < 0 || chars_total_shadow < visible_chars) {
- CharType c = xl_text[i + pos];
- CharType n = xl_text[i + pos + 1];
+ char32_t c = xl_text[i + pos];
+ char32_t n = xl_text[i + pos + 1];
if (uppercase) {
c = String::char_uppercase(c);
n = String::char_uppercase(n);
@@ -255,8 +255,8 @@ void Label::_notification(int p_what) {
}
for (int i = 0; i < from->word_len; i++) {
if (visible_chars < 0 || chars_total < visible_chars) {
- CharType c = xl_text[i + pos];
- CharType n = xl_text[i + pos + 1];
+ char32_t c = xl_text[i + pos];
+ char32_t n = xl_text[i + pos + 1];
if (uppercase) {
c = String::char_uppercase(c);
n = String::char_uppercase(n);
@@ -308,7 +308,7 @@ int Label::get_longest_line_width() const {
real_t line_width = 0;
for (int i = 0; i < xl_text.size(); i++) {
- CharType current = xl_text[i];
+ char32_t current = xl_text[i];
if (uppercase) {
current = String::char_uppercase(current);
}
@@ -390,7 +390,7 @@ void Label::regenerate_word_cache() {
WordCache *last = nullptr;
for (int i = 0; i <= xl_text.length(); i++) {
- CharType current = i < xl_text.length() ? xl_text[i] : L' '; //always a space at the end, so the algo works
+ char32_t current = i < xl_text.length() ? xl_text[i] : L' '; //always a space at the end, so the algo works
if (uppercase) {
current = String::char_uppercase(current);
@@ -420,6 +420,22 @@ void Label::regenerate_word_cache() {
wc->space_count = space_count;
current_word_size = 0;
space_count = 0;
+ } else if ((i == xl_text.length() || current == '\n') && last != nullptr && space_count != 0) {
+ //in case there are trailing white spaces we add a placeholder word cache with just the spaces
+ WordCache *wc = memnew(WordCache);
+ if (word_cache) {
+ last->next = wc;
+ } else {
+ word_cache = wc;
+ }
+ last = wc;
+
+ wc->pixel_width = 0;
+ wc->char_pos = 0;
+ wc->word_len = 0;
+ wc->space_count = space_count;
+ current_word_size = 0;
+ space_count = 0;
}
if (current == '\n') {
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 14167531a5..8b95acff70 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -42,7 +42,7 @@
#include "editor/editor_settings.h"
#endif
#include "scene/main/window.h"
-static bool _is_text_char(CharType c) {
+static bool _is_text_char(char32_t c) {
return !is_symbol(c);
}
@@ -582,7 +582,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
if (k->get_unicode() >= 32 && k->get_keycode() != KEY_DELETE) {
if (editable) {
selection_delete();
- CharType ucodestr[2] = { (CharType)k->get_unicode(), 0 };
+ char32_t ucodestr[2] = { (char32_t)k->get_unicode(), 0 };
int prev_len = text.length();
append_at_cursor(ucodestr);
if (text.length() != prev_len) {
@@ -807,8 +807,8 @@ void LineEdit::_notification(int p_what) {
break;
}
- CharType cchar = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs];
- CharType next = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs + 1];
+ char32_t cchar = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs];
+ char32_t next = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs + 1];
int im_char_width = font->get_char_size(cchar, next).width;
if ((x_ofs + im_char_width) > ofs_max) {
@@ -830,8 +830,8 @@ void LineEdit::_notification(int p_what) {
}
}
- CharType cchar = (pass && !text.empty()) ? secret_character[0] : t[char_ofs];
- CharType next = (pass && !text.empty()) ? secret_character[0] : t[char_ofs + 1];
+ char32_t cchar = (pass && !text.empty()) ? secret_character[0] : t[char_ofs];
+ char32_t next = (pass && !text.empty()) ? secret_character[0] : t[char_ofs + 1];
int char_width = font->get_char_size(cchar, next).width;
// End of widget, break.
@@ -870,8 +870,8 @@ void LineEdit::_notification(int p_what) {
break;
}
- CharType cchar = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs];
- CharType next = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs + 1];
+ char32_t cchar = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs];
+ char32_t next = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs + 1];
int im_char_width = font->get_char_size(cchar, next).width;
if ((x_ofs + im_char_width) > ofs_max) {
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index 5fc5f9b669..8a65aa5032 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -41,55 +41,71 @@ void Popup::_input_from_window(const Ref<InputEvent> &p_event) {
}
}
-void Popup::_parent_focused() {
- _close_pressed();
+void Popup::_initialize_visible_parents() {
+ visible_parents.clear();
+
+ Window *parent_window = this;
+ while (parent_window) {
+ parent_window = parent_window->get_parent_visible_window();
+ if (parent_window) {
+ visible_parents.push_back(parent_window);
+ parent_window->connect("focus_entered", callable_mp(this, &Popup::_parent_focused));
+ parent_window->connect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents));
+ }
+ }
+}
+
+void Popup::_deinitialize_visible_parents() {
+ for (uint32_t i = 0; i < visible_parents.size(); ++i) {
+ visible_parents[i]->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused));
+ visible_parents[i]->disconnect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents));
+ }
+
+ visible_parents.clear();
}
void Popup::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
if (is_visible()) {
- parent_visible = get_parent_visible_window();
- if (parent_visible) {
- parent_visible->connect("focus_entered", callable_mp(this, &Popup::_parent_focused));
- }
+ _initialize_visible_parents();
} else {
- if (parent_visible) {
- parent_visible->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused));
- parent_visible = nullptr;
- }
-
+ _deinitialize_visible_parents();
emit_signal("popup_hide");
}
} break;
- case NOTIFICATION_EXIT_TREE: {
- if (parent_visible) {
- parent_visible->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused));
- parent_visible = nullptr;
+ case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
+ if (has_focus()) {
+ popped_up = true;
}
} break;
+ case NOTIFICATION_EXIT_TREE: {
+ _deinitialize_visible_parents();
+ } break;
case NOTIFICATION_WM_CLOSE_REQUEST: {
_close_pressed();
-
+ } break;
+ case NOTIFICATION_APPLICATION_FOCUS_OUT: {
+ _close_pressed();
} break;
}
}
-void Popup::_close_pressed() {
- Window *parent_window = parent_visible;
- if (parent_visible) {
- parent_visible->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused));
- parent_visible = nullptr;
+void Popup::_parent_focused() {
+ if (popped_up) {
+ _close_pressed();
}
+}
+
+void Popup::_close_pressed() {
+ popped_up = false;
+
+ _deinitialize_visible_parents();
call_deferred("hide");
emit_signal("cancelled");
-
- if (parent_window) {
- //parent_window->grab_focus();
- }
}
void Popup::set_as_minsize() {
@@ -126,12 +142,32 @@ Rect2i Popup::_popup_adjust_rect() const {
current.position.y = parent.position.y;
}
+ if (current.size.y > parent.size.y) {
+ current.size.y = parent.size.y;
+ }
+
+ if (current.size.x > parent.size.x) {
+ current.size.x = parent.size.x;
+ }
+
+ // Early out if max size not set.
+ Size2i max_size = get_max_size();
+ if (max_size <= Size2()) {
+ return current;
+ }
+
+ if (current.size.x > max_size.x) {
+ current.size.x = max_size.x;
+ }
+
+ if (current.size.y > max_size.y) {
+ current.size.y = max_size.y;
+ }
+
return current;
}
Popup::Popup() {
- parent_visible = nullptr;
-
set_wrap_controls(true);
set_visible(false);
set_transient(true);
diff --git a/scene/gui/popup.h b/scene/gui/popup.h
index 97c08095d3..3e5b89ccf3 100644
--- a/scene/gui/popup.h
+++ b/scene/gui/popup.h
@@ -33,12 +33,19 @@
#include "scene/main/window.h"
+#include "core/local_vector.h"
+
class Popup : public Window {
GDCLASS(Popup, Window);
- Window *parent_visible;
+ LocalVector<Window *> visible_parents;
+ bool popped_up = false;
void _input_from_window(const Ref<InputEvent> &p_event);
+
+ void _initialize_visible_parents();
+ void _deinitialize_visible_parents();
+
void _parent_focused();
protected:
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 6e19b820e0..2fdcf11ca8 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -35,7 +35,6 @@
#include "core/os/os.h"
#include "core/print_string.h"
#include "core/translation.h"
-#include "scene/gui/control.h"
String PopupMenu::_get_accel_text(int p_item) const {
ERR_FAIL_INDEX_V(p_item, items.size(), String());
@@ -52,7 +51,8 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
int vseparation = get_theme_constant("vseparation");
int hseparation = get_theme_constant("hseparation");
- Size2 minsize = get_theme_stylebox("panel")->get_minimum_size();
+ Size2 minsize = get_theme_stylebox("panel")->get_minimum_size(); // Accounts for margin in the margin container
+ minsize.x += scroll_container->get_v_scrollbar()->get_size().width * 2; // Adds a buffer so that the scrollbar does not render over the top of content
Ref<Font> font = get_theme_font("font");
float max_w = 0;
@@ -64,13 +64,10 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
for (int i = 0; i < items.size(); i++) {
Size2 size;
- if (!items[i].icon.is_null()) {
- Size2 icon_size = items[i].icon->get_size();
- size.height = MAX(icon_size.height, font_h);
- icon_w = MAX(icon_size.width + hseparation, icon_w);
- } else {
- size.height = font_h;
- }
+
+ Size2 icon_size = items[i].get_icon_size();
+ size.height = MAX(icon_size.height, font_h);
+ icon_w = MAX(icon_size.width, icon_w);
size.width += items[i].h_ofs;
@@ -104,39 +101,71 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
minsize.width += check_w;
}
+ if (is_inside_tree()) {
+ int height_limit = get_usable_parent_rect().size.height;
+ if (minsize.height > height_limit) {
+ minsize.height = height_limit;
+ }
+ }
+
return minsize;
}
+int PopupMenu::_get_items_total_height() const {
+ int font_height = get_theme_font("font")->get_height();
+ int vsep = get_theme_constant("vseparation");
+
+ // Get total height of all items by taking max of icon height and font height
+ int items_total_height = 0;
+ for (int i = 0; i < items.size(); i++) {
+ items_total_height += MAX(items[i].get_icon_size().height, font_height) + vsep;
+ }
+
+ // Subtract a separator which is not needed for the last item.
+ return items_total_height - vsep;
+}
+
+void PopupMenu::_scroll_to_item(int p_item) {
+ ERR_FAIL_INDEX(p_item, items.size());
+ ERR_FAIL_COND(p_item < 0);
+
+ // Scroll item into view (upwards)
+ if (items[p_item]._ofs_cache < -control->get_position().y) {
+ int amnt_over = items[p_item]._ofs_cache + control->get_position().y;
+ scroll_container->set_v_scroll(scroll_container->get_v_scroll() + amnt_over);
+ }
+
+ // Scroll item into view (downwards)
+ if (items[p_item]._ofs_cache + items[p_item]._height_cache > -control->get_position().y + scroll_container->get_size().height) {
+ int amnt_over = items[p_item]._ofs_cache + items[p_item]._height_cache + control->get_position().y - scroll_container->get_size().height;
+ scroll_container->set_v_scroll(scroll_container->get_v_scroll() + amnt_over);
+ }
+}
+
int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
if (p_over.x < 0 || p_over.x >= get_size().width) {
return -1;
}
- Ref<StyleBox> style = get_theme_stylebox("panel");
+ Ref<StyleBox> style = get_theme_stylebox("panel"); // Accounts for margin in the margin container
+
+ int vseparation = get_theme_constant("vseparation");
+ float font_h = get_theme_font("font")->get_height();
- Point2 ofs = style->get_offset();
+ Point2 ofs = style->get_offset() + Point2(0, vseparation / 2);
if (ofs.y > p_over.y) {
return -1;
}
- Ref<Font> font = get_theme_font("font");
- int vseparation = get_theme_constant("vseparation");
- float font_h = font->get_height();
-
for (int i = 0; i < items.size(); i++) {
- ofs.y += vseparation;
- float h;
-
- if (!items[i].icon.is_null()) {
- Size2 icon_size = items[i].icon->get_size();
- h = MAX(icon_size.height, font_h);
- } else {
- h = font_h;
+ if (i > 0) {
+ ofs.y += vseparation;
}
- ofs.y += h;
- if (p_over.y < ofs.y) {
+ ofs.y += MAX(items[i].get_icon_size().height, font_h);
+
+ if (p_over.y - control->get_position().y < ofs.y) {
return i;
}
}
@@ -147,43 +176,51 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
void PopupMenu::_activate_submenu(int over) {
Node *n = get_node(items[over].submenu);
ERR_FAIL_COND_MSG(!n, "Item subnode does not exist: " + items[over].submenu + ".");
- Popup *pm = Object::cast_to<Popup>(n);
- ERR_FAIL_COND_MSG(!pm, "Item subnode is not a Popup: " + items[over].submenu + ".");
- if (pm->is_visible()) {
+ Popup *submenu_popup = Object::cast_to<Popup>(n);
+ ERR_FAIL_COND_MSG(!submenu_popup, "Item subnode is not a Popup: " + items[over].submenu + ".");
+ if (submenu_popup->is_visible()) {
return; //already visible!
}
- Point2 p = get_position();
- Rect2 pr(p, get_size());
Ref<StyleBox> style = get_theme_stylebox("panel");
+ int vsep = get_theme_constant("vseparation");
+
+ Point2 this_pos = get_position();
+ Rect2 this_rect(this_pos, get_size());
+
+ float scroll_offset = control->get_position().y;
- Point2 pos = p + Point2(get_size().width, items[over]._ofs_cache - style->get_offset().y);
- Size2 size = pm->get_size();
- // fix pos
- if (pos.x + size.width > get_parent_rect().size.width) {
- pos.x = p.x - size.width;
+ Point2 submenu_pos = this_pos + Point2(this_rect.size.width, items[over]._ofs_cache + scroll_offset);
+ Size2 submenu_size = submenu_popup->get_size();
+
+ // Fix pos if going outside parent rect
+ if (submenu_pos.x + submenu_size.width > get_parent_rect().size.width) {
+ submenu_pos.x = this_pos.x - submenu_size.width;
}
- pm->set_position(pos);
- // pm->set_scale(get_global_transform().get_scale());
- pm->popup();
-
- PopupMenu *pum = Object::cast_to<PopupMenu>(pm);
- if (pum) {
- pr.position -= pum->get_position();
- pum->clear_autohide_areas();
- pum->add_autohide_area(Rect2(pr.position.x, pr.position.y, pr.size.x, items[over]._ofs_cache));
- if (over < items.size() - 1) {
- int from = items[over + 1]._ofs_cache;
- pum->add_autohide_area(Rect2(pr.position.x, pr.position.y + from, pr.size.x, pr.size.y - from));
+ submenu_popup->set_position(submenu_pos);
+ submenu_popup->set_as_minsize(); // Shrink the popup size to it's contents.
+ submenu_popup->popup();
+
+ // Set autohide areas
+ PopupMenu *submenu_pum = Object::cast_to<PopupMenu>(submenu_popup);
+ if (submenu_pum) {
+ // Make the position of the parent popup relative to submenu popup
+ this_rect.position = this_rect.position - submenu_pum->get_position();
+
+ // Autohide area above the submenu item
+ submenu_pum->clear_autohide_areas();
+ submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y, this_rect.size.x, items[over]._ofs_cache + scroll_offset + style->get_offset().height - vsep / 2));
+
+ // If there is an area below the submenu item, add an autohide area there.
+ if (items[over]._ofs_cache + items[over]._height_cache + scroll_offset <= control->get_size().height) {
+ int from = items[over]._ofs_cache + items[over]._height_cache + scroll_offset + vsep / 2 + style->get_offset().height;
+ submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y + from, this_rect.size.x, this_rect.size.y - from));
}
}
}
void PopupMenu::_submenu_timeout() {
- //if (!has_focus()) {
- // return; //do not activate if not has focus
- //}
if (mouse_over == submenu_over) {
_activate_submenu(mouse_over);
}
@@ -191,70 +228,34 @@ void PopupMenu::_submenu_timeout() {
submenu_over = -1;
}
-void PopupMenu::_scroll(float p_factor, const Point2 &p_over) {
- int vseparation = get_theme_constant("vseparation");
- Ref<Font> font = get_theme_font("font");
-
- Rect2 visible_rect = get_usable_parent_rect();
-
- int dy = (vseparation + font->get_height()) * 3 * p_factor;
- if (dy > 0) {
- const float global_top = get_position().y;
- const float limit = global_top < visible_rect.position.y ? visible_rect.position.y - global_top : 0;
- dy = MIN(dy, limit);
- } else if (dy < 0) {
- const float global_bottom = get_position().y + get_size().y;
- const float viewport_height = visible_rect.position.y + visible_rect.size.y;
- const float limit = global_bottom > viewport_height ? global_bottom - viewport_height : 0;
- dy = -MIN(-dy, limit);
- }
-
- if (dy == 0) {
- return;
- }
-
- set_position(get_position() + Vector2(0, dy));
-
- Ref<InputEventMouseMotion> ie;
- ie.instance();
- ie->set_position(p_over - Vector2(0, dy));
- _gui_input(ie);
-}
-
void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
- if (p_event->is_action("ui_down") && p_event->is_pressed()) {
+ if (p_event->is_action("ui_down") && p_event->is_pressed() && mouse_over != items.size() - 1) {
int search_from = mouse_over + 1;
if (search_from >= items.size()) {
search_from = 0;
}
for (int i = search_from; i < items.size(); i++) {
- if (i < 0 || i >= items.size()) {
- continue;
- }
-
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
emit_signal("id_focused", i);
+ _scroll_to_item(i);
control->update();
set_input_as_handled();
break;
}
}
- } else if (p_event->is_action("ui_up") && p_event->is_pressed()) {
+ } else if (p_event->is_action("ui_up") && p_event->is_pressed() && mouse_over != 0) {
int search_from = mouse_over - 1;
if (search_from < 0) {
search_from = items.size() - 1;
}
for (int i = search_from; i >= 0; i--) {
- if (i >= items.size()) {
- continue;
- }
-
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
emit_signal("id_focused", i);
+ _scroll_to_item(i);
control->update();
set_input_as_handled();
break;
@@ -282,60 +283,61 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
}
}
+ // Make an area which does not include v scrollbar, so that items are not activated when dragging scrollbar.
+ Rect2 item_clickable_area = scroll_container->get_rect();
+ if (scroll_container->get_v_scrollbar()->is_visible_in_tree()) {
+ item_clickable_area.size.width -= scroll_container->get_v_scrollbar()->get_size().width;
+ }
+
Ref<InputEventMouseButton> b = p_event;
if (b.is_valid()) {
- if (b->is_pressed()) {
+ if (!item_clickable_area.has_point(b->get_position())) {
return;
}
int button_idx = b->get_button_index();
- switch (button_idx) {
- case BUTTON_WHEEL_DOWN: {
- _scroll(-b->get_factor(), b->get_position());
- } break;
- case BUTTON_WHEEL_UP: {
- _scroll(b->get_factor(), b->get_position());
- } break;
- default: {
- // Allow activating item by releasing the LMB or any that was down when the popup appeared
- if (button_idx == BUTTON_LEFT || (initial_button_mask & (1 << (button_idx - 1)))) {
- bool was_during_grabbed_click = during_grabbed_click;
- during_grabbed_click = false;
- initial_button_mask = 0;
-
- int over = _get_mouse_over(b->get_position());
-
- if (invalidated_click) {
- invalidated_click = false;
- break;
- }
- if (over < 0) {
- if (!was_during_grabbed_click) {
- hide();
- }
- break; //non-activable
+ if (b->is_pressed() || (!b->is_pressed() && during_grabbed_click)) {
+ // Allow activating item by releasing the LMB or any that was down when the popup appeared.
+ // However, if button was not held when opening menu, do not allow release to activate item.
+ if (button_idx == BUTTON_LEFT || (initial_button_mask & (1 << (button_idx - 1)))) {
+ bool was_during_grabbed_click = during_grabbed_click;
+ during_grabbed_click = false;
+ initial_button_mask = 0;
+
+ int over = _get_mouse_over(b->get_position());
+
+ if (invalidated_click) {
+ invalidated_click = false;
+ return;
+ }
+ if (over < 0) {
+ if (!was_during_grabbed_click) {
+ hide();
}
+ return;
+ }
- if (items[over].separator || items[over].disabled) {
- break;
- }
+ if (items[over].separator || items[over].disabled) {
+ return;
+ }
- if (items[over].submenu != "") {
- _activate_submenu(over);
- return;
- }
- activate_item(over);
+ if (items[over].submenu != "") {
+ _activate_submenu(over);
+ return;
}
+ activate_item(over);
}
}
-
- //control->update();
}
Ref<InputEventMouseMotion> m = p_event;
if (m.is_valid()) {
+ if (!item_clickable_area.has_point(m->get_position())) {
+ return;
+ }
+
if (invalidated_click) {
moved += m->get_relative();
if (moved.length() > 4) {
@@ -370,11 +372,6 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- Ref<InputEventPanGesture> pan_gesture = p_event;
- if (pan_gesture.is_valid()) {
- _scroll(-pan_gesture->get_delta().y, pan_gesture->get_position());
- }
-
Ref<InputEventKey> k = p_event;
if (allow_search && k.is_valid() && k->get_unicode() && k->is_pressed()) {
@@ -407,6 +404,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
if (items[i].text.findn(search_string) == 0) {
mouse_over = i;
emit_signal("id_focused", i);
+ _scroll_to_item(i);
control->update();
set_input_as_handled();
break;
@@ -415,9 +413,13 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
}
}
-void PopupMenu::_draw() {
+void PopupMenu::_draw_items() {
+ control->set_custom_minimum_size(Size2(0, _get_items_total_height()));
RID ci = control->get_canvas_item();
- Size2 size = get_size();
+
+ Size2 margin_size;
+ margin_size.width = margin_container->get_theme_constant("margin_right") + margin_container->get_theme_constant("margin_left");
+ margin_size.height = margin_container->get_theme_constant("margin_top") + margin_container->get_theme_constant("margin_bottom");
Ref<StyleBox> style = get_theme_stylebox("panel");
Ref<StyleBox> hover = get_theme_stylebox("hover");
@@ -430,8 +432,6 @@ void PopupMenu::_draw() {
Ref<StyleBox> labeled_separator_left = get_theme_stylebox("labeled_separator_left");
Ref<StyleBox> labeled_separator_right = get_theme_stylebox("labeled_separator_right");
- style->draw(ci, Rect2(Point2(), get_size()));
- Point2 ofs = style->get_offset();
int vseparation = get_theme_constant("vseparation");
int hseparation = get_theme_constant("hseparation");
Color font_color = get_theme_color("font_color");
@@ -440,13 +440,14 @@ void PopupMenu::_draw() {
Color font_color_hover = get_theme_color("font_color_hover");
float font_h = font->get_height();
- // Add the check and the wider icon to the offset of all items.
+ float scroll_width = scroll_container->get_v_scrollbar()->is_visible_in_tree() ? scroll_container->get_v_scrollbar()->get_size().width : 0;
+ float display_width = control->get_size().width - scroll_width;
+
+ // Find the widest icon and whether any items have a checkbox, and store the offsets for each.
float icon_ofs = 0.0;
bool has_check = false;
for (int i = 0; i < items.size(); i++) {
- if (!items[i].icon.is_null()) {
- icon_ofs = MAX(items[i].icon->get_size().width, icon_ofs);
- }
+ icon_ofs = MAX(items[i].get_icon_size().width, icon_ofs);
if (items[i].checkable_type) {
has_check = true;
@@ -461,65 +462,68 @@ void PopupMenu::_draw() {
check_ofs = MAX(get_theme_icon("checked")->get_width(), get_theme_icon("radio_checked")->get_width()) + hseparation;
}
+ Point2 ofs = Point2();
+
+ // Loop through all items and draw each.
for (int i = 0; i < items.size(); i++) {
+ // If not the first item, add the separation space between items.
if (i > 0) {
ofs.y += vseparation;
}
- Point2 item_ofs = ofs;
- Size2 icon_size;
- float h;
- if (!items[i].icon.is_null()) {
- icon_size = items[i].icon->get_size();
- h = MAX(icon_size.height, font_h);
- } else {
- h = font_h;
- }
+ Point2 item_ofs = ofs;
+ Size2 icon_size = items[i].get_icon_size();
+ float h = MAX(icon_size.height, font_h);
if (i == mouse_over) {
- hover->draw(ci, Rect2(item_ofs + Point2(-hseparation, -vseparation / 2), Size2(get_size().width - style->get_minimum_size().width + hseparation * 2, h + vseparation)));
+ hover->draw(ci, Rect2(item_ofs + Point2(-hseparation, -vseparation / 2), Size2(display_width + hseparation * 2, h + vseparation)));
}
String text = items[i].xl_text;
+ // Separator
item_ofs.x += items[i].h_ofs;
if (items[i].separator) {
int sep_h = separator->get_center_size().height + separator->get_minimum_size().height;
if (text != String()) {
- int ss = font->get_string_size(text).width;
- int center = (get_size().width) / 2;
- int l = center - ss / 2;
- int r = center + ss / 2;
- if (l > item_ofs.x) {
- labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, l - item_ofs.x), sep_h)));
+ int text_size = font->get_string_size(text).width;
+ int text_center = display_width / 2;
+ int text_left = text_center - text_size / 2;
+ int text_right = text_center + text_size / 2;
+ if (text_left > item_ofs.x) {
+ labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, text_left - item_ofs.x), sep_h)));
}
- if (r < get_size().width - style->get_margin(MARGIN_RIGHT)) {
- labeled_separator_right->draw(ci, Rect2(Point2(r, item_ofs.y + Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, get_size().width - style->get_margin(MARGIN_RIGHT) - r), sep_h)));
+ if (text_right < display_width) {
+ labeled_separator_right->draw(ci, Rect2(Point2(text_right, item_ofs.y + Math::floor((h - sep_h) / 2.0)), Size2(MAX(0, display_width - text_right), sep_h)));
}
} else {
- separator->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(get_size().width - style->get_minimum_size().width, sep_h)));
+ separator->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(display_width, sep_h)));
}
}
Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1);
+ // Checkboxes
if (items[i].checkable_type) {
Texture2D *icon = (items[i].checked ? check[items[i].checkable_type - 1] : uncheck[items[i].checkable_type - 1]).ptr();
icon->draw(ci, item_ofs + Point2(0, Math::floor((h - icon->get_height()) / 2.0)), icon_color);
}
+ // Icon
if (!items[i].icon.is_null()) {
items[i].icon->draw(ci, item_ofs + Size2(check_ofs, 0) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color);
}
+ // Submenu arrow on right hand side
if (items[i].submenu != "") {
- submenu->draw(ci, Point2(size.width - style->get_margin(MARGIN_RIGHT) - submenu->get_width(), item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
+ submenu->draw(ci, Point2(display_width - submenu->get_width(), item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color);
}
+ // Text
item_ofs.y += font->get_ascent();
if (items[i].separator) {
if (text != String()) {
- int center = (get_size().width - font->get_string_size(text).width) / 2;
+ int center = (display_width - font->get_string_size(text).width) / 2;
font->draw(ci, Point2(center, item_ofs.y + Math::floor((h - font_h) / 2.0)), text, font_color_disabled);
}
} else {
@@ -527,19 +531,27 @@ void PopupMenu::_draw() {
font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text, items[i].disabled ? font_color_disabled : (i == mouse_over ? font_color_hover : font_color));
}
+ // Accelerator / Shortcut
if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->is_valid())) {
- //accelerator
- String text2 = _get_accel_text(i);
- item_ofs.x = size.width - style->get_margin(MARGIN_RIGHT) - font->get_string_size(text2).width;
- font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), text2, i == mouse_over ? font_color_hover : font_color_accel);
+ String sc_text = _get_accel_text(i);
+ item_ofs.x = display_width - font->get_string_size(sc_text).width;
+ font->draw(ci, item_ofs + Point2(0, Math::floor((h - font_h) / 2.0)), sc_text, i == mouse_over ? font_color_hover : font_color_accel);
}
+ // Cache the item vertical offset from the first item and the height
items.write[i]._ofs_cache = ofs.y;
+ items.write[i]._height_cache = h;
ofs.y += h;
}
}
+void PopupMenu::_draw_background() {
+ Ref<StyleBox> style = get_theme_stylebox("panel");
+ RID ci2 = margin_container->get_canvas_item();
+ style->draw(ci2, Rect2(Point2(), margin_container->get_size()));
+}
+
void PopupMenu::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -617,6 +629,13 @@ void PopupMenu::_notification(int p_what) {
if (get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
set_process_internal(true);
}
+
+ // Set margin on the margin container
+ Ref<StyleBox> panel_style = get_theme_stylebox("panel");
+ margin_container->add_theme_constant_override("margin_top", panel_style->get_margin(Margin::MARGIN_TOP));
+ margin_container->add_theme_constant_override("margin_bottom", panel_style->get_margin(Margin::MARGIN_BOTTOM));
+ margin_container->add_theme_constant_override("margin_left", panel_style->get_margin(Margin::MARGIN_LEFT));
+ margin_container->add_theme_constant_override("margin_right", panel_style->get_margin(Margin::MARGIN_RIGHT));
}
} break;
}
@@ -1425,16 +1444,32 @@ void PopupMenu::_bind_methods() {
void PopupMenu::popup(const Rect2 &p_bounds) {
moved = Vector2();
invalidated_click = true;
+ set_as_minsize();
Popup::popup(p_bounds);
}
PopupMenu::PopupMenu() {
+ // Margin Container
+ margin_container = memnew(MarginContainer);
+ margin_container->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ add_child(margin_container);
+ margin_container->connect("draw", callable_mp(this, &PopupMenu::_draw_background));
+
+ // Scroll Container
+ scroll_container = memnew(ScrollContainer);
+ scroll_container->set_clip_contents(true);
+ margin_container->add_child(scroll_container);
+
+ // The control which will display the items
control = memnew(Control);
- add_child(control);
-
+ control->set_clip_contents(false);
control->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ control->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ control->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ scroll_container->add_child(control);
+ control->connect("draw", callable_mp(this, &PopupMenu::_draw_items));
+
connect("window_input", callable_mp(this, &PopupMenu::_gui_input));
- control->connect("draw", callable_mp(this, &PopupMenu::_draw));
mouse_over = -1;
submenu_over = -1;
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index 43cd7a54e9..45a3336747 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -31,7 +31,9 @@
#ifndef POPUP_MENU_H
#define POPUP_MENU_H
+#include "scene/gui/margin_container.h"
#include "scene/gui/popup.h"
+#include "scene/gui/scroll_container.h"
#include "scene/gui/shortcut.h"
class PopupMenu : public Popup {
@@ -57,11 +59,17 @@ class PopupMenu : public Popup {
String tooltip;
uint32_t accel;
int _ofs_cache;
+ int _height_cache;
int h_ofs;
Ref<ShortCut> shortcut;
bool shortcut_is_global;
bool shortcut_is_disabled;
+ // Returns (0,0) if icon is null.
+ Size2 get_icon_size() const {
+ return icon.is_null() ? Size2() : icon->get_size();
+ }
+
Item() {
checked = false;
checkable_type = CHECKABLE_TYPE_NONE;
@@ -71,6 +79,7 @@ class PopupMenu : public Popup {
accel = 0;
disabled = false;
_ofs_cache = 0;
+ _height_cache = 0;
h_ofs = 0;
shortcut_is_global = false;
shortcut_is_disabled = false;
@@ -88,7 +97,10 @@ class PopupMenu : public Popup {
String _get_accel_text(int p_item) const;
int _get_mouse_over(const Point2 &p_over) const;
virtual Size2 _get_contents_minimum_size() const override;
- void _scroll(float p_factor, const Point2 &p_over);
+
+ int _get_items_total_height() const;
+ void _scroll_to_item(int p_item);
+
void _gui_input(const Ref<InputEvent> &p_event);
void _activate_submenu(int over);
void _submenu_timeout();
@@ -111,9 +123,12 @@ class PopupMenu : public Popup {
uint64_t search_time_msec;
String search_string;
+ MarginContainer *margin_container;
+ ScrollContainer *scroll_container;
Control *control;
- void _draw();
+ void _draw_items();
+ void _draw_background();
protected:
friend class MenuButton;
diff --git a/scene/gui/rich_text_effect.h b/scene/gui/rich_text_effect.h
index 77c82aa780..a5401f7eaa 100644
--- a/scene/gui/rich_text_effect.h
+++ b/scene/gui/rich_text_effect.h
@@ -59,7 +59,7 @@ public:
bool visibility;
Point2 offset;
Color color;
- CharType character;
+ char32_t character;
float elapsed_time;
Dictionary environment;
@@ -79,7 +79,7 @@ public:
Color get_color() { return color; }
void set_color(Color p_color) { color = p_color; }
int get_character() { return (int)character; }
- void set_character(int p_char) { character = (CharType)p_char; }
+ void set_character(int p_char) { character = (char32_t)p_char; }
Dictionary get_environment() { return environment; }
void set_environment(Dictionary p_environment) { environment = p_environment; }
};
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 29337e20f3..c62fd24a5e 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -354,8 +354,8 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
font = p_base_font;
}
- const CharType *c = text->text.c_str();
- const CharType *cf = c;
+ const char32_t *c = text->text.get_data();
+ const char32_t *cf = c;
int ascent = font->get_ascent();
int descent = font->get_descent();
@@ -461,7 +461,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
bool selected = false;
Color fx_color = Color(color);
Point2 fx_offset;
- CharType fx_char = c[i];
+ char32_t fx_char = c[i];
if (selection.active) {
int cofs = (&c[i]) - cf;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index d6d8e74748..1d732bec5b 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -44,23 +44,23 @@
#define TAB_PIXELS
-inline bool _is_symbol(CharType c) {
+inline bool _is_symbol(char32_t c) {
return is_symbol(c);
}
-static bool _is_text_char(CharType c) {
+static bool _is_text_char(char32_t c) {
return !is_symbol(c);
}
-static bool _is_whitespace(CharType c) {
+static bool _is_whitespace(char32_t c) {
return c == '\t' || c == ' ';
}
-static bool _is_char(CharType c) {
+static bool _is_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
}
-static bool _is_pair_right_symbol(CharType c) {
+static bool _is_pair_right_symbol(char32_t c) {
return c == '"' ||
c == '\'' ||
c == ')' ||
@@ -68,7 +68,7 @@ static bool _is_pair_right_symbol(CharType c) {
c == '}';
}
-static bool _is_pair_left_symbol(CharType c) {
+static bool _is_pair_left_symbol(char32_t c) {
return c == '"' ||
c == '\'' ||
c == '(' ||
@@ -76,11 +76,11 @@ static bool _is_pair_left_symbol(CharType c) {
c == '{';
}
-static bool _is_pair_symbol(CharType c) {
+static bool _is_pair_symbol(char32_t c) {
return _is_pair_left_symbol(c) || _is_pair_right_symbol(c);
}
-static CharType _get_right_pair_symbol(CharType c) {
+static char32_t _get_right_pair_symbol(char32_t c) {
if (c == '"') {
return '"';
}
@@ -119,7 +119,7 @@ void TextEdit::Text::_update_line_cache(int p_line) const {
int w = 0;
int len = text[p_line].data.length();
- const CharType *str = text[p_line].data.c_str();
+ const char32_t *str = text[p_line].data.get_data();
// Update width.
@@ -214,7 +214,7 @@ void TextEdit::Text::remove(int p_at) {
text.remove(p_at);
}
-int TextEdit::Text::get_char_width(CharType c, CharType next_c, int px) const {
+int TextEdit::Text::get_char_width(char32_t c, char32_t next_c, int px) const {
int tab_w = font->get_char_size(' ').width * indent_size;
int w = 0;
@@ -654,8 +654,8 @@ void TextEdit::_notification(int p_what) {
if (brace_matching_enabled && cursor.line >= 0 && cursor.line < text.size() && cursor.column >= 0) {
if (cursor.column < text[cursor.line].length()) {
// Check for open.
- CharType c = text[cursor.line][cursor.column];
- CharType closec = 0;
+ char32_t c = text[cursor.line][cursor.column];
+ char32_t closec = 0;
if (c == '[') {
closec = ']';
@@ -671,10 +671,10 @@ void TextEdit::_notification(int p_what) {
for (int i = cursor.line; i < text.size(); i++) {
int from = i == cursor.line ? cursor.column + 1 : 0;
for (int j = from; j < text[i].length(); j++) {
- CharType cc = text[i][j];
+ char32_t cc = text[i][j];
// Ignore any brackets inside a string.
if (cc == '"' || cc == '\'') {
- CharType quotation = cc;
+ char32_t quotation = cc;
do {
j++;
if (!(j < text[i].length())) {
@@ -720,8 +720,8 @@ void TextEdit::_notification(int p_what) {
}
if (cursor.column > 0) {
- CharType c = text[cursor.line][cursor.column - 1];
- CharType closec = 0;
+ char32_t c = text[cursor.line][cursor.column - 1];
+ char32_t closec = 0;
if (c == ']') {
closec = '[';
@@ -737,10 +737,10 @@ void TextEdit::_notification(int p_what) {
for (int i = cursor.line; i >= 0; i--) {
int from = i == cursor.line ? cursor.column - 2 : text[i].length() - 1;
for (int j = from; j >= 0; j--) {
- CharType cc = text[i][j];
+ char32_t cc = text[i][j];
// Ignore any brackets inside a string.
if (cc == '"' || cc == '\'') {
- CharType quotation = cc;
+ char32_t quotation = cc;
do {
j--;
if (!(j >= 0)) {
@@ -1303,8 +1303,8 @@ void TextEdit::_notification(int p_what) {
break;
}
- CharType cchar = ime_text[ofs];
- CharType next = ime_text[ofs + 1];
+ char32_t cchar = ime_text[ofs];
+ char32_t next = ime_text[ofs + 1];
int im_char_width = cache.font->get_char_size(cchar, next).width;
if ((char_ofs + char_margin + im_char_width) >= xmargin_end) {
@@ -1399,8 +1399,8 @@ void TextEdit::_notification(int p_what) {
break;
}
- CharType cchar = ime_text[ofs];
- CharType next = ime_text[ofs + 1];
+ char32_t cchar = ime_text[ofs];
+ char32_t next = ime_text[ofs + 1];
int im_char_width = cache.font->get_char_size(cchar, next).width;
if ((char_ofs + char_margin + im_char_width) >= xmargin_end) {
@@ -1661,12 +1661,12 @@ void TextEdit::_notification(int p_what) {
}
}
-void TextEdit::_consume_pair_symbol(CharType ch) {
+void TextEdit::_consume_pair_symbol(char32_t ch) {
int cursor_position_to_move = cursor_get_column() + 1;
- CharType ch_single[2] = { ch, 0 };
- CharType ch_single_pair[2] = { _get_right_pair_symbol(ch), 0 };
- CharType ch_pair[3] = { ch, _get_right_pair_symbol(ch), 0 };
+ char32_t ch_single[2] = { ch, 0 };
+ char32_t ch_single_pair[2] = { _get_right_pair_symbol(ch), 0 };
+ char32_t ch_pair[3] = { ch, _get_right_pair_symbol(ch), 0 };
if (is_selection_active()) {
int new_column, new_line;
@@ -1771,8 +1771,8 @@ void TextEdit::_consume_backspace_for_pair_symbol(int prev_line, int prev_column
bool remove_right_symbol = false;
if (cursor.column < text[cursor.line].length() && cursor.column > 0) {
- CharType left_char = text[cursor.line][cursor.column - 1];
- CharType right_char = text[cursor.line][cursor.column];
+ char32_t left_char = text[cursor.line][cursor.column - 1];
+ char32_t right_char = text[cursor.line][cursor.column];
if (right_char == _get_right_pair_symbol(left_char)) {
remove_right_symbol = true;
@@ -2540,7 +2540,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (k->get_unicode() > 32) {
_reset_caret_blink_timer();
- const CharType chr[2] = { (CharType)k->get_unicode(), 0 };
+ const char32_t chr[2] = { (char32_t)k->get_unicode(), 0 };
if (auto_brace_completion_enabled && _is_pair_symbol(chr[0])) {
_consume_pair_symbol(chr[0]);
} else {
@@ -2784,7 +2784,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
// No need to move the brace below if we are not taking the text with us.
- char closing_char = _get_right_pair_symbol(indent_char);
+ char32_t closing_char = _get_right_pair_symbol(indent_char);
if ((closing_char != 0) && (closing_char == text[cursor.line][cursor.column]) && !k->get_command()) {
brace_indent = true;
ins += "\n" + ins.substr(1, ins.length() - 2);
@@ -3312,7 +3312,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
// Compute whitespace symbols seq length.
int current_line_whitespace_len = 0;
while (current_line_whitespace_len < text[cursor.line].length()) {
- CharType c = text[cursor.line][current_line_whitespace_len];
+ char32_t c = text[cursor.line][current_line_whitespace_len];
if (c != '\t' && c != ' ') {
break;
}
@@ -3458,7 +3458,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
int current_line_whitespace_len = 0;
while (current_line_whitespace_len < text[cursor.line].length()) {
- CharType c = text[cursor.line][current_line_whitespace_len];
+ char32_t c = text[cursor.line][current_line_whitespace_len];
if (c != '\t' && c != ' ')
break;
current_line_whitespace_len++;
@@ -3624,7 +3624,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
}
- const CharType chr[2] = { (CharType)k->get_unicode(), 0 };
+ const char32_t chr[2] = { (char32_t)k->get_unicode(), 0 };
if (completion_hint != "" && k->get_unicode() == ')') {
completion_hint = "";
@@ -4251,7 +4251,7 @@ Vector<String> TextEdit::get_wrap_rows_text(int p_line) const {
}
while (col < line_text.length()) {
- CharType c = line_text[col];
+ char32_t c = line_text[col];
int w = text.get_char_width(c, line_text[col + 1], px + word_px);
int indent_ofs = (cur_wrap_index != 0 ? tab_offset_px : 0);
@@ -6115,9 +6115,9 @@ void TextEdit::_confirm_completion() {
// When inserted into the middle of an existing string/method, don't add an unnecessary quote/bracket.
String line = text[cursor.line];
- CharType next_char = line[cursor.column];
- CharType last_completion_char = completion_current.insert_text[completion_current.insert_text.length() - 1];
- CharType last_completion_char_display = completion_current.display[completion_current.display.length() - 1];
+ char32_t next_char = line[cursor.column];
+ char32_t last_completion_char = completion_current.insert_text[completion_current.insert_text.length() - 1];
+ char32_t last_completion_char_display = completion_current.display[completion_current.display.length() - 1];
if ((last_completion_char == '"' || last_completion_char == '\'') && (last_completion_char == next_char || last_completion_char_display == next_char)) {
_remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1);
@@ -6161,7 +6161,7 @@ void TextEdit::_cancel_completion() {
update();
}
-static bool _is_completable(CharType c) {
+static bool _is_completable(char32_t c) {
return !_is_symbol(c) || c == '"' || c == '\'';
}
@@ -6292,14 +6292,14 @@ void TextEdit::_update_completion_candidates() {
String display_lower = option.display.to_lower();
- const CharType *ssq = &s[0];
- const CharType *ssq_lower = &s_lower[0];
+ const char32_t *ssq = &s[0];
+ const char32_t *ssq_lower = &s_lower[0];
- const CharType *tgt = &option.display[0];
- const CharType *tgt_lower = &display_lower[0];
+ const char32_t *tgt = &option.display[0];
+ const char32_t *tgt_lower = &display_lower[0];
- const CharType *ssq_last_tgt = nullptr;
- const CharType *ssq_lower_last_tgt = nullptr;
+ const char32_t *ssq_last_tgt = nullptr;
+ const char32_t *ssq_lower_last_tgt = nullptr;
for (; *tgt; tgt++, tgt_lower++) {
if (*ssq == *tgt) {
@@ -6416,7 +6416,7 @@ String TextEdit::get_word_at_pos(const Vector2 &p_pos) const {
int beg, end;
if (select_word(s, col, beg, end)) {
bool inside_quotes = false;
- CharType selected_quote = '\0';
+ char32_t selected_quote = '\0';
int qbegin = 0, qend = 0;
for (int i = 0; i < s.length(); i++) {
if (s[i] == '"' || s[i] == '\'') {
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index a6bc9963cc..70d7365d71 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -79,7 +79,7 @@ public:
void set_font(const Ref<Font> &p_font);
int get_line_width(int p_line) const;
int get_max_width(bool p_exclude_hidden = false) const;
- int get_char_width(CharType c, CharType next_c, int px) const;
+ int get_char_width(char32_t c, char32_t next_c, int px) const;
void set_line_wrap_amount(int p_line, int p_wrap_amount) const;
int get_line_wrap_amount(int p_line) const;
void set(int p_line, const String &p_text);
@@ -488,7 +488,7 @@ protected:
void _gui_input(const Ref<InputEvent> &p_gui_input);
void _notification(int p_what);
- void _consume_pair_symbol(CharType ch);
+ void _consume_pair_symbol(char32_t ch);
void _consume_backspace_for_pair_symbol(int prev_line, int prev_column);
static void _bind_methods();
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index d6d1134cc9..5cd45ea408 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -939,9 +939,9 @@ float CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const
ERR_FAIL_COND_V(p_font.is_null(), 0);
if (p_font->has_outline()) {
- p_font->draw_char(canvas_item, p_pos, p_char[0], p_next.c_str()[0], Color(1, 1, 1), true);
+ p_font->draw_char(canvas_item, p_pos, p_char[0], p_next.get_data()[0], Color(1, 1, 1), true);
}
- return p_font->draw_char(canvas_item, p_pos, p_char[0], p_next.c_str()[0], p_modulate);
+ return p_font->draw_char(canvas_item, p_pos, p_char[0], p_next.get_data()[0], p_modulate);
}
void CanvasItem::_notify_transform(CanvasItem *p_node) {
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 653eb698d4..e7753089c7 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -1094,7 +1094,7 @@ String increase_numeric_string(const String &s) {
if (!carry) {
break;
}
- CharType n = s[i];
+ char32_t n = s[i];
if (n == '9') { // keep carry as true: 9 + 1
res[i] = '0';
} else {
@@ -1155,7 +1155,7 @@ void Node::_generate_serial_child_name(const Node *p_child, StringName &name) co
String name_string = name;
String nums;
for (int i = name_string.length() - 1; i >= 0; i--) {
- CharType n = name_string[i];
+ char32_t n = name_string[i];
if (n >= '0' && n <= '9') {
nums = String::chr(name_string[i]) + nums;
} else {
@@ -1327,6 +1327,9 @@ int Node::get_child_count() const {
}
Node *Node::get_child(int p_index) const {
+ if (p_index < 0) {
+ p_index += data.children.size();
+ }
ERR_FAIL_INDEX_V(p_index, data.children.size(), nullptr);
return data.children[p_index];
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 68ffdfe2e8..7c2350d1c0 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -246,7 +246,10 @@ void Window::_make_window() {
}
}
+ _update_window_callbacks();
+
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE);
+ DisplayServer::get_singleton()->show_window(window_id);
}
void Window::_update_from_window() {
@@ -378,7 +381,6 @@ void Window::set_visible(bool p_visible) {
}
if (p_visible && window_id == DisplayServer::INVALID_WINDOW_ID) {
_make_window();
- _update_window_callbacks();
}
} else {
if (visible) {
@@ -737,7 +739,6 @@ void Window::_notification(int p_what) {
//create
if (visible) {
_make_window();
- _update_window_callbacks();
}
}
}
diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp
index 99f87dd6ed..bc983c1d7e 100644
--- a/scene/resources/dynamic_font.cpp
+++ b/scene/resources/dynamic_font.cpp
@@ -239,7 +239,7 @@ float DynamicFontAtSize::get_underline_thickness() const {
return underline_thickness;
}
-const Pair<const DynamicFontAtSize::Character *, DynamicFontAtSize *> DynamicFontAtSize::_find_char_with_font(CharType p_char, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const {
+const Pair<const DynamicFontAtSize::Character *, DynamicFontAtSize *> DynamicFontAtSize::_find_char_with_font(char32_t p_char, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const {
const Character *chr = char_map.getptr(p_char);
ERR_FAIL_COND_V(!chr, (Pair<const Character *, DynamicFontAtSize *>(nullptr, nullptr)));
@@ -271,7 +271,7 @@ const Pair<const DynamicFontAtSize::Character *, DynamicFontAtSize *> DynamicFon
return Pair<const Character *, DynamicFontAtSize *>(chr, const_cast<DynamicFontAtSize *>(this));
}
-Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const {
+Size2 DynamicFontAtSize::get_char_size(char32_t p_char, char32_t p_next, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const {
if (!valid) {
return Size2(1, 1);
}
@@ -297,7 +297,7 @@ String DynamicFontAtSize::get_available_chars() const {
FT_ULong charcode = FT_Get_First_Char(face, &gindex);
while (gindex != 0) {
if (charcode != 0) {
- chars += CharType(charcode);
+ chars += char32_t(charcode);
}
charcode = FT_Get_Next_Char(face, charcode, &gindex);
}
@@ -305,7 +305,7 @@ String DynamicFontAtSize::get_available_chars() const {
return chars;
}
-float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks, bool p_advance_only, bool p_outline) const {
+float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks, bool p_advance_only, bool p_outline) const {
if (!valid) {
return 0;
}
@@ -560,7 +560,7 @@ DynamicFontAtSize::Character DynamicFontAtSize::_bitmap_to_character(FT_Bitmap b
return chr;
}
-DynamicFontAtSize::Character DynamicFontAtSize::_make_outline_char(CharType p_char) {
+DynamicFontAtSize::Character DynamicFontAtSize::_make_outline_char(char32_t p_char) {
Character ret = Character::not_found();
if (FT_Load_Char(face, p_char, FT_LOAD_NO_BITMAP | (font->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)) != 0) {
@@ -596,7 +596,7 @@ cleanup_stroker:
return ret;
}
-void DynamicFontAtSize::_update_char(CharType p_char) {
+void DynamicFontAtSize::_update_char(char32_t p_char) {
if (char_map.has(p_char)) {
return;
}
@@ -849,7 +849,7 @@ float DynamicFont::get_underline_thickness() const {
return data_at_size->get_underline_thickness();
}
-Size2 DynamicFont::get_char_size(CharType p_char, CharType p_next) const {
+Size2 DynamicFont::get_char_size(char32_t p_char, char32_t p_next) const {
if (!data_at_size.is_valid()) {
return Size2(1, 1);
}
@@ -891,7 +891,7 @@ bool DynamicFont::has_outline() const {
return outline_cache_id.outline_size > 0;
}
-float DynamicFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, bool p_outline) const {
+float DynamicFont::draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next, const Color &p_modulate, bool p_outline) const {
const Ref<DynamicFontAtSize> &font_at_size = p_outline && outline_cache_id.outline_size > 0 ? outline_data_at_size : data_at_size;
if (!font_at_size.is_valid()) {
diff --git a/scene/resources/dynamic_font.h b/scene/resources/dynamic_font.h
index e8637e7e34..a881e21da8 100644
--- a/scene/resources/dynamic_font.h
+++ b/scene/resources/dynamic_font.h
@@ -159,17 +159,17 @@ class DynamicFontAtSize : public Reference {
int y;
};
- const Pair<const Character *, DynamicFontAtSize *> _find_char_with_font(CharType p_char, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const;
- Character _make_outline_char(CharType p_char);
+ const Pair<const Character *, DynamicFontAtSize *> _find_char_with_font(char32_t p_char, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const;
+ Character _make_outline_char(char32_t p_char);
TexturePosition _find_texture_pos_for_glyph(int p_color_size, Image::Format p_image_format, int p_width, int p_height);
Character _bitmap_to_character(FT_Bitmap bitmap, int yofs, int xofs, float advance);
static unsigned long _ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count);
static void _ft_stream_close(FT_Stream stream);
- HashMap<CharType, Character> char_map;
+ HashMap<char32_t, Character> char_map;
- _FORCE_INLINE_ void _update_char(CharType p_char);
+ _FORCE_INLINE_ void _update_char(char32_t p_char);
friend class DynamicFontData;
Ref<DynamicFontData> font;
@@ -188,10 +188,10 @@ public:
float get_underline_position() const;
float get_underline_thickness() const;
- Size2 get_char_size(CharType p_char, CharType p_next, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const;
+ Size2 get_char_size(char32_t p_char, char32_t p_next, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks) const;
String get_available_chars() const;
- float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks, bool p_advance_only = false, bool p_outline = false) const;
+ float draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize>> &p_fallbacks, bool p_advance_only = false, bool p_outline = false) const;
void set_texture_flags(uint32_t p_flags);
void update_oversampling();
@@ -277,14 +277,14 @@ public:
virtual float get_underline_position() const override;
virtual float get_underline_thickness() const override;
- virtual Size2 get_char_size(CharType p_char, CharType p_next = 0) const override;
+ virtual Size2 get_char_size(char32_t p_char, char32_t p_next = 0) const override;
String get_available_chars() const;
virtual bool is_distance_field_hint() const override;
virtual bool has_outline() const override;
- virtual float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const override;
+ virtual float draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const override;
SelfList<DynamicFont> font_list;
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index ccab88a153..7cc39f661d 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -125,7 +125,7 @@ void BitmapFont::_set_chars(const Vector<int> &p_chars) {
Vector<int> BitmapFont::_get_chars() const {
Vector<int> chars;
- const CharType *key = nullptr;
+ const char32_t *key = nullptr;
while ((key = char_map.next(key))) {
const Character *c = char_map.getptr(*key);
@@ -272,7 +272,7 @@ Error BitmapFont::create_from_fnt(const String &p_file) {
}
}
} else if (type == "char") {
- CharType idx = 0;
+ char32_t idx = 0;
if (keys.has("id")) {
idx = keys["id"].to_int();
}
@@ -313,7 +313,7 @@ Error BitmapFont::create_from_fnt(const String &p_file) {
add_char(idx, texture, rect, ofs, advance);
} else if (type == "kerning") {
- CharType first = 0, second = 0;
+ char32_t first = 0, second = 0;
int k = 0;
if (keys.has("first")) {
@@ -385,10 +385,10 @@ int BitmapFont::get_character_count() const {
return char_map.size();
};
-Vector<CharType> BitmapFont::get_char_keys() const {
- Vector<CharType> chars;
+Vector<char32_t> BitmapFont::get_char_keys() const {
+ Vector<char32_t> chars;
chars.resize(char_map.size());
- const CharType *ct = nullptr;
+ const char32_t *ct = nullptr;
int count = 0;
while ((ct = char_map.next(ct))) {
chars.write[count++] = *ct;
@@ -397,7 +397,7 @@ Vector<CharType> BitmapFont::get_char_keys() const {
return chars;
};
-BitmapFont::Character BitmapFont::get_character(CharType p_char) const {
+BitmapFont::Character BitmapFont::get_character(char32_t p_char) const {
if (!char_map.has(p_char)) {
ERR_FAIL_V(Character());
};
@@ -405,7 +405,7 @@ BitmapFont::Character BitmapFont::get_character(CharType p_char) const {
return char_map[p_char];
};
-void BitmapFont::add_char(CharType p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) {
+void BitmapFont::add_char(char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) {
if (p_advance < 0) {
p_advance = p_rect.size.width;
}
@@ -420,7 +420,7 @@ void BitmapFont::add_char(CharType p_char, int p_texture_idx, const Rect2 &p_rec
char_map[p_char] = c;
}
-void BitmapFont::add_kerning_pair(CharType p_A, CharType p_B, int p_kerning) {
+void BitmapFont::add_kerning_pair(char32_t p_A, char32_t p_B, int p_kerning) {
KerningPairKey kpk;
kpk.A = p_A;
kpk.B = p_B;
@@ -444,7 +444,7 @@ Vector<BitmapFont::KerningPairKey> BitmapFont::get_kerning_pair_keys() const {
return ret;
}
-int BitmapFont::get_kerning_pair(CharType p_A, CharType p_B) const {
+int BitmapFont::get_kerning_pair(char32_t p_A, char32_t p_B) const {
KerningPairKey kpk;
kpk.A = p_A;
kpk.B = p_B;
@@ -482,7 +482,7 @@ Size2 Font::get_string_size(const String &p_string) const {
if (l == 0) {
return Size2(0, get_height());
}
- const CharType *sptr = &p_string[0];
+ const char32_t *sptr = &p_string[0];
for (int i = 0; i < l; i++) {
w += get_char_size(sptr[i], sptr[i + 1]).width;
@@ -534,7 +534,7 @@ Ref<BitmapFont> BitmapFont::get_fallback() const {
return fallback;
}
-float BitmapFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, bool p_outline) const {
+float BitmapFont::draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next, const Color &p_modulate, bool p_outline) const {
const Character *c = char_map.getptr(p_char);
if (!c) {
@@ -556,7 +556,7 @@ float BitmapFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_c
return get_char_size(p_char, p_next).width;
}
-Size2 BitmapFont::get_char_size(CharType p_char, CharType p_next) const {
+Size2 BitmapFont::get_char_size(char32_t p_char, char32_t p_next) const {
const Character *c = char_map.getptr(p_char);
if (!c) {
diff --git a/scene/resources/font.h b/scene/resources/font.h
index e6b296800b..c739520da3 100644
--- a/scene/resources/font.h
+++ b/scene/resources/font.h
@@ -49,7 +49,7 @@ public:
virtual float get_underline_position() const = 0;
virtual float get_underline_thickness() const = 0;
- virtual Size2 get_char_size(CharType p_char, CharType p_next = 0) const = 0;
+ virtual Size2 get_char_size(char32_t p_char, char32_t p_next = 0) const = 0;
Size2 get_string_size(const String &p_string) const;
Size2 get_wordwrap_string_size(const String &p_string, float p_width) const;
@@ -59,7 +59,7 @@ public:
void draw_halign(RID p_canvas_item, const Point2 &p_pos, HAlign p_align, float p_width, const String &p_text, const Color &p_modulate = Color(1, 1, 1), const Color &p_outline_modulate = Color(1, 1, 1)) const;
virtual bool has_outline() const { return false; }
- virtual float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const = 0;
+ virtual float draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const = 0;
void update_changes();
Font();
@@ -74,8 +74,8 @@ class FontDrawer {
struct PendingDraw {
RID canvas_item;
Point2 pos;
- CharType chr;
- CharType next;
+ char32_t chr;
+ char32_t next;
Color modulate;
};
@@ -88,7 +88,7 @@ public:
has_outline = p_font->has_outline();
}
- float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1)) {
+ float draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next = 0, const Color &p_modulate = Color(1, 1, 1)) {
if (has_outline) {
PendingDraw draw = { p_canvas_item, p_pos, p_char, p_next, p_modulate };
pending_draws.push_back(draw);
@@ -137,7 +137,7 @@ public:
};
private:
- HashMap<CharType, Character> char_map;
+ HashMap<char32_t, Character> char_map;
Map<KerningPairKey, int> kerning_map;
float height;
@@ -169,20 +169,20 @@ public:
float get_underline_thickness() const override;
void add_texture(const Ref<Texture2D> &p_texture);
- void add_char(CharType p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance = -1);
+ void add_char(char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance = -1);
int get_character_count() const;
- Vector<CharType> get_char_keys() const;
- Character get_character(CharType p_char) const;
+ Vector<char32_t> get_char_keys() const;
+ Character get_character(char32_t p_char) const;
int get_texture_count() const;
Ref<Texture2D> get_texture(int p_idx) const;
- void add_kerning_pair(CharType p_A, CharType p_B, int p_kerning);
- int get_kerning_pair(CharType p_A, CharType p_B) const;
+ void add_kerning_pair(char32_t p_A, char32_t p_B, int p_kerning);
+ int get_kerning_pair(char32_t p_A, char32_t p_B) const;
Vector<KerningPairKey> get_kerning_pair_keys() const;
- Size2 get_char_size(CharType p_char, CharType p_next = 0) const override;
+ Size2 get_char_size(char32_t p_char, char32_t p_next = 0) const override;
void set_fallback(const Ref<BitmapFont> &p_fallback);
Ref<BitmapFont> get_fallback() const;
@@ -192,7 +192,7 @@ public:
void set_distance_field_hint(bool p_distance_field);
bool is_distance_field_hint() const override;
- float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const override;
+ float draw_char(RID p_canvas_item, const Point2 &p_pos, char32_t p_char, char32_t p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const override;
BitmapFont();
~BitmapFont();
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index fd1fa1b48f..b0a30a5627 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -209,7 +209,6 @@ public:
void surface_update_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data);
int get_surface_count() const override;
- void surface_remove(int p_idx);
void clear_surfaces();
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp
index fc92a721db..49b8cbe7e0 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particles_material.cpp
@@ -91,13 +91,13 @@ void ParticlesMaterial::init_shaders() {
shader_names->emission_texture_normal = "emission_texture_normal";
shader_names->emission_texture_color = "emission_texture_color";
- shader_names->trail_divisor = "trail_divisor";
- shader_names->trail_size_modifier = "trail_size_modifier";
- shader_names->trail_color_modifier = "trail_color_modifier";
-
shader_names->gravity = "gravity";
shader_names->lifetime_randomness = "lifetime_randomness";
+
+ shader_names->sub_emitter_frequency = "sub_emitter_frequency";
+ shader_names->sub_emitter_amount_at_end = "sub_emitter_amount_at_end";
+ shader_names->sub_emitter_keep_velocity = "sub_emitter_keep_velocity";
}
void ParticlesMaterial::finish_shaders() {
@@ -192,9 +192,17 @@ void ParticlesMaterial::_update_shader() {
}
}
- code += "uniform vec4 color_value : hint_color;\n";
+ if (sub_emitter_mode != SUB_EMITTER_DISABLED) {
+ if (sub_emitter_mode == SUB_EMITTER_CONSTANT) {
+ code += "uniform float sub_emitter_frequency;\n";
+ }
+ if (sub_emitter_mode == SUB_EMITTER_AT_END) {
+ code += "uniform int sub_emitter_amount_at_end;\n";
+ }
+ code += "uniform bool sub_emitter_keep_velocity;\n";
+ }
- code += "uniform int trail_divisor;\n";
+ code += "uniform vec4 color_value : hint_color;\n";
code += "uniform vec3 gravity;\n";
@@ -239,14 +247,6 @@ void ParticlesMaterial::_update_shader() {
code += "uniform sampler2D anim_offset_texture;\n";
}
- if (trail_size_modifier.is_valid()) {
- code += "uniform sampler2D trail_size_modifier;\n";
- }
-
- if (trail_color_modifier.is_valid()) {
- code += "uniform sampler2D trail_color_modifier;\n";
- }
-
//need a random function
code += "\n\n";
code += "float rand_from_seed(inout uint seed) {\n";
@@ -277,8 +277,8 @@ void ParticlesMaterial::_update_shader() {
code += "}\n";
code += "\n";
- code += "void vertex() {\n";
- code += " uint base_number = NUMBER / uint(trail_divisor);\n";
+ code += "void compute() {\n";
+ code += " uint base_number = NUMBER;\n";
code += " uint alt_seed = hash(base_number + uint(1) + RANDOM_SEED);\n";
code += " float angle_rand = rand_from_seed(alt_seed);\n";
code += " float scale_rand = rand_from_seed(alt_seed);\n";
@@ -293,17 +293,7 @@ void ParticlesMaterial::_update_shader() {
code += " ivec2 emission_tex_size = textureSize(emission_texture_points, 0);\n";
code += " ivec2 emission_tex_ofs = ivec2(point % emission_tex_size.x, point / emission_tex_size.x);\n";
}
- code += " bool restart = false;\n";
- code += " if (CUSTOM.y > CUSTOM.w) {\n";
- code += " restart = true;\n";
- code += " }\n\n";
- code += " if (RESTART || restart) {\n";
-
- if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
- code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(0.0, 0.0), 0.0).r;\n";
- } else {
- code += " float tex_linear_velocity = 0.0;\n";
- }
+ code += " if (RESTART) {\n";
if (tex_parameters[PARAM_ANGLE].is_valid()) {
code += " float tex_angle = textureLod(angle_texture, vec2(0.0, 0.0), 0.0).r;\n";
@@ -319,25 +309,34 @@ void ParticlesMaterial::_update_shader() {
code += " float spread_rad = spread * degree_to_rad;\n";
+ code += " if (RESTART_VELOCITY) {\n";
+
+ if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
+ code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(0.0, 0.0), 0.0).r;\n";
+ } else {
+ code += " float tex_linear_velocity = 0.0;\n";
+ }
+
if (flags[FLAG_DISABLE_Z]) {
- code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n";
- code += " angle1_rad += direction.x != 0.0 ? atan(direction.y, direction.x) : sign(direction.y) * (pi / 2.0);\n";
- code += " vec3 rot = vec3(cos(angle1_rad), sin(angle1_rad), 0.0);\n";
- code += " VELOCITY = rot * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
+ code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n";
+ code += " angle1_rad += direction.x != 0.0 ? atan(direction.y, direction.x) : sign(direction.y) * (pi / 2.0);\n";
+ code += " vec3 rot = vec3(cos(angle1_rad), sin(angle1_rad), 0.0);\n";
+ code += " VELOCITY = rot * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
} else {
//initiate velocity spread in 3D
- code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n";
- code += " float angle2_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad * (1.0 - flatness);\n";
- code += " angle1_rad += direction.z != 0.0 ? atan(direction.x, direction.z) : sign(direction.x) * (pi / 2.0);\n";
- code += " angle2_rad += direction.z != 0.0 ? atan(direction.y, abs(direction.z)) : (direction.x != 0.0 ? atan(direction.y, abs(direction.x)) : sign(direction.y) * (pi / 2.0));\n";
- code += " vec3 direction_xz = vec3(sin(angle1_rad), 0.0, cos(angle1_rad));\n";
- code += " vec3 direction_yz = vec3(0.0, sin(angle2_rad), cos(angle2_rad));\n";
- code += " direction_yz.z = direction_yz.z / max(0.0001,sqrt(abs(direction_yz.z))); // better uniform distribution\n";
- code += " vec3 vec_direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n";
- code += " vec_direction = normalize(vec_direction);\n";
- code += " VELOCITY = vec_direction * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
+ code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n";
+ code += " float angle2_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad * (1.0 - flatness);\n";
+ code += " angle1_rad += direction.z != 0.0 ? atan(direction.x, direction.z) : sign(direction.x) * (pi / 2.0);\n";
+ code += " angle2_rad += direction.z != 0.0 ? atan(direction.y, abs(direction.z)) : (direction.x != 0.0 ? atan(direction.y, abs(direction.x)) : sign(direction.y) * (pi / 2.0));\n";
+ code += " vec3 direction_xz = vec3(sin(angle1_rad), 0.0, cos(angle1_rad));\n";
+ code += " vec3 direction_yz = vec3(0.0, sin(angle2_rad), cos(angle2_rad));\n";
+ code += " direction_yz.z = direction_yz.z / max(0.0001,sqrt(abs(direction_yz.z))); // better uniform distribution\n";
+ code += " vec3 vec_direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n";
+ code += " vec_direction = normalize(vec_direction);\n";
+ code += " VELOCITY = vec_direction * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
}
+ code += " }\n";
code += " float base_angle = (initial_angle + tex_angle) * mix(1.0, angle_rand, initial_angle_random);\n";
code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle
@@ -345,35 +344,38 @@ void ParticlesMaterial::_update_shader() {
code += " CUSTOM.w = (1.0 - lifetime_randomness * rand_from_seed(alt_seed));\n";
code += " CUSTOM.z = (anim_offset + tex_anim_offset) * mix(1.0, anim_offset_rand, anim_offset_random);\n"; // animation offset (0-1)
+ code += " if (RESTART_POSITION) {\n";
+
switch (emission_shape) {
case EMISSION_SHAPE_POINT: {
- //do none
+ //do none, identity (will later be multiplied by emission transform)
+ code += " TRANSFORM = mat4(vec4(1,0,0,0),vec4(0,1,0,0),vec4(0,0,1,0),vec4(0,0,0,1));\n";
} break;
case EMISSION_SHAPE_SPHERE: {
- code += " float s = rand_from_seed(alt_seed) * 2.0 - 1.0;\n";
- code += " float t = rand_from_seed(alt_seed) * 2.0 * pi;\n";
- code += " float radius = emission_sphere_radius * sqrt(1.0 - s * s);\n";
- code += " TRANSFORM[3].xyz = vec3(radius * cos(t), radius * sin(t), emission_sphere_radius * s);\n";
+ code += " float s = rand_from_seed(alt_seed) * 2.0 - 1.0;\n";
+ code += " float t = rand_from_seed(alt_seed) * 2.0 * pi;\n";
+ code += " float radius = emission_sphere_radius * sqrt(1.0 - s * s);\n";
+ code += " TRANSFORM[3].xyz = vec3(radius * cos(t), radius * sin(t), emission_sphere_radius * s);\n";
} break;
case EMISSION_SHAPE_BOX: {
- code += " TRANSFORM[3].xyz = vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0) * emission_box_extents;\n";
+ code += " TRANSFORM[3].xyz = vec3(rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, rand_from_seed(alt_seed) * 2.0 - 1.0) * emission_box_extents;\n";
} break;
case EMISSION_SHAPE_POINTS:
case EMISSION_SHAPE_DIRECTED_POINTS: {
- code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs, 0).xyz;\n";
+ code += " TRANSFORM[3].xyz = texelFetch(emission_texture_points, emission_tex_ofs, 0).xyz;\n";
if (emission_shape == EMISSION_SHAPE_DIRECTED_POINTS) {
if (flags[FLAG_DISABLE_Z]) {
- code += " mat2 rotm;";
- code += " rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;\n";
- code += " rotm[1] = rotm[0].yx * vec2(1.0, -1.0);\n";
- code += " VELOCITY.xy = rotm * VELOCITY.xy;\n";
+ code += " mat2 rotm;";
+ code += " rotm[0] = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xy;\n";
+ code += " rotm[1] = rotm[0].yx * vec2(1.0, -1.0);\n";
+ code += " if (RESTART_VELOCITY) VELOCITY.xy = rotm * VELOCITY.xy;\n";
} else {
- code += " vec3 normal = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xyz;\n";
- code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);\n";
- code += " vec3 tangent = normalize(cross(v0, normal));\n";
- code += " vec3 bitangent = normalize(cross(tangent, normal));\n";
- code += " VELOCITY = mat3(tangent, bitangent, normal) * VELOCITY;\n";
+ code += " vec3 normal = texelFetch(emission_texture_normal, emission_tex_ofs, 0).xyz;\n";
+ code += " vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);\n";
+ code += " vec3 tangent = normalize(cross(v0, normal));\n";
+ code += " vec3 bitangent = normalize(cross(tangent, normal));\n";
+ code += " if (RESTART_VELOCITY) VELOCITY = mat3(tangent, bitangent, normal) * VELOCITY;\n";
}
}
} break;
@@ -381,12 +383,14 @@ void ParticlesMaterial::_update_shader() {
break;
}
}
- code += " VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n";
- code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n";
+
+ code += " if (RESTART_VELOCITY) VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n";
+ code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n";
if (flags[FLAG_DISABLE_Z]) {
- code += " VELOCITY.z = 0.0;\n";
- code += " TRANSFORM[3].z = 0.0;\n";
+ code += " VELOCITY.z = 0.0;\n";
+ code += " TRANSFORM[3].z = 0.0;\n";
}
+ code += " }\n";
code += " } else {\n";
@@ -540,11 +544,6 @@ void ParticlesMaterial::_update_shader() {
if (emission_color_texture.is_valid() && (emission_shape == EMISSION_SHAPE_POINTS || emission_shape == EMISSION_SHAPE_DIRECTED_POINTS)) {
code += " COLOR *= texelFetch(emission_texture_color, emission_tex_ofs, 0);\n";
}
- if (trail_color_modifier.is_valid()) {
- code += " if (trail_divisor > 1) {\n";
- code += " COLOR *= textureLod(trail_color_modifier, vec2(float(int(NUMBER) % trail_divisor) / float(trail_divisor - 1), 0.0), 0.0);\n";
- code += " }\n";
- }
code += "\n";
if (flags[FLAG_DISABLE_Z]) {
@@ -592,11 +591,6 @@ void ParticlesMaterial::_update_shader() {
code += " if (base_scale < 0.000001) {\n";
code += " base_scale = 0.000001;\n";
code += " }\n";
- if (trail_size_modifier.is_valid()) {
- code += " if (trail_divisor > 1) {\n";
- code += " base_scale *= textureLod(trail_size_modifier, vec2(float(int(NUMBER) % trail_divisor) / float(trail_divisor - 1), 0.0), 0.0).r;\n";
- code += " }\n";
- }
code += " TRANSFORM[0].xyz *= base_scale;\n";
code += " TRANSFORM[1].xyz *= base_scale;\n";
@@ -605,6 +599,33 @@ void ParticlesMaterial::_update_shader() {
code += " VELOCITY.z = 0.0;\n";
code += " TRANSFORM[3].z = 0.0;\n";
}
+ if (sub_emitter_mode != SUB_EMITTER_DISABLED) {
+ code += " int emit_count = 0;\n";
+ switch (sub_emitter_mode) {
+ case SUB_EMITTER_CONSTANT: {
+ code += " float interval_from = CUSTOM.y * LIFETIME - DELTA;\n";
+ code += " float interval_rem = sub_emitter_frequency - mod(interval_from,sub_emitter_frequency);\n";
+ code += " if (DELTA >= interval_rem) emit_count = 1;\n";
+ } break;
+ case SUB_EMITTER_AT_COLLISION: {
+ //not implemented yet
+ } break;
+ case SUB_EMITTER_AT_END: {
+ //not implemented yet
+ code += " float unit_delta = DELTA/LIFETIME;\n";
+ code += " float end_time = CUSTOM.w * 0.95;\n"; // if we do at the end we might miss it, as it can just get deactivated by emitter
+ code += " if (CUSTOM.y < end_time && (CUSTOM.y + unit_delta) >= end_time) emit_count = sub_emitter_amount_at_end;\n";
+ } break;
+ default: {
+ }
+ }
+ code += " for(int i=0;i<emit_count;i++) {\n";
+ code += " uint flags = FLAG_EMIT_POSITION|FLAG_EMIT_ROT_SCALE;\n";
+ code += " if (sub_emitter_keep_velocity) flags|=FLAG_EMIT_VELOCITY;\n";
+ code += " emit_particle(TRANSFORM,VELOCITY,vec4(0.0),vec4(0.0),flags);\n";
+ code += " }";
+ }
+
code += " if (CUSTOM.y > CUSTOM.w) {";
code += " ACTIVE = false;\n";
code += " }\n";
@@ -951,41 +972,6 @@ int ParticlesMaterial::get_emission_point_count() const {
return emission_point_count;
}
-void ParticlesMaterial::set_trail_divisor(int p_divisor) {
- trail_divisor = p_divisor;
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_divisor, p_divisor);
-}
-
-int ParticlesMaterial::get_trail_divisor() const {
- return trail_divisor;
-}
-
-void ParticlesMaterial::set_trail_size_modifier(const Ref<CurveTexture> &p_trail_size_modifier) {
- trail_size_modifier = p_trail_size_modifier;
-
- Ref<CurveTexture> curve = trail_size_modifier;
- if (curve.is_valid()) {
- curve->ensure_default_setup();
- }
-
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, curve);
- _queue_shader_change();
-}
-
-Ref<CurveTexture> ParticlesMaterial::get_trail_size_modifier() const {
- return trail_size_modifier;
-}
-
-void ParticlesMaterial::set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier) {
- trail_color_modifier = p_trail_color_modifier;
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, p_trail_color_modifier);
- _queue_shader_change();
-}
-
-Ref<GradientTexture> ParticlesMaterial::get_trail_color_modifier() const {
- return trail_color_modifier;
-}
-
void ParticlesMaterial::set_gravity(const Vector3 &p_gravity) {
gravity = p_gravity;
Vector3 gset = gravity;
@@ -1038,11 +1024,54 @@ void ParticlesMaterial::_validate_property(PropertyInfo &property) const {
property.usage = 0;
}
+ if (property.name == "sub_emitter_frequency" && sub_emitter_mode != SUB_EMITTER_CONSTANT) {
+ property.usage = 0;
+ }
+
+ if (property.name == "sub_emitter_amount_at_end" && sub_emitter_mode != SUB_EMITTER_AT_END) {
+ property.usage = 0;
+ }
+
if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) {
property.usage = 0;
}
}
+void ParticlesMaterial::set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode) {
+ sub_emitter_mode = p_sub_emitter_mode;
+ _queue_shader_change();
+ _change_notify();
+}
+
+ParticlesMaterial::SubEmitterMode ParticlesMaterial::get_sub_emitter_mode() const {
+ return sub_emitter_mode;
+}
+
+void ParticlesMaterial::set_sub_emitter_frequency(float p_frequency) {
+ sub_emitter_frequency = p_frequency;
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_frequency, 1.0 / p_frequency); //pas delta instead of frequency, since its easier to compute
+}
+float ParticlesMaterial::get_sub_emitter_frequency() const {
+ return sub_emitter_frequency;
+}
+
+void ParticlesMaterial::set_sub_emitter_amount_at_end(int p_amount) {
+ sub_emitter_amount_at_end = p_amount;
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_amount_at_end, p_amount);
+}
+
+int ParticlesMaterial::get_sub_emitter_amount_at_end() const {
+ return sub_emitter_amount_at_end;
+}
+
+void ParticlesMaterial::set_sub_emitter_keep_velocity(bool p_enable) {
+ sub_emitter_keep_velocity = p_enable;
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_keep_velocity, p_enable);
+}
+bool ParticlesMaterial::get_sub_emitter_keep_velocity() const {
+ return sub_emitter_keep_velocity;
+}
+
Shader::Mode ParticlesMaterial::get_shader_mode() const {
return Shader::MODE_PARTICLES;
}
@@ -1096,27 +1125,27 @@ void ParticlesMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_emission_point_count", "point_count"), &ParticlesMaterial::set_emission_point_count);
ClassDB::bind_method(D_METHOD("get_emission_point_count"), &ParticlesMaterial::get_emission_point_count);
- ClassDB::bind_method(D_METHOD("set_trail_divisor", "divisor"), &ParticlesMaterial::set_trail_divisor);
- ClassDB::bind_method(D_METHOD("get_trail_divisor"), &ParticlesMaterial::get_trail_divisor);
-
- ClassDB::bind_method(D_METHOD("set_trail_size_modifier", "texture"), &ParticlesMaterial::set_trail_size_modifier);
- ClassDB::bind_method(D_METHOD("get_trail_size_modifier"), &ParticlesMaterial::get_trail_size_modifier);
-
- ClassDB::bind_method(D_METHOD("set_trail_color_modifier", "texture"), &ParticlesMaterial::set_trail_color_modifier);
- ClassDB::bind_method(D_METHOD("get_trail_color_modifier"), &ParticlesMaterial::get_trail_color_modifier);
-
ClassDB::bind_method(D_METHOD("get_gravity"), &ParticlesMaterial::get_gravity);
ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &ParticlesMaterial::set_gravity);
ClassDB::bind_method(D_METHOD("set_lifetime_randomness", "randomness"), &ParticlesMaterial::set_lifetime_randomness);
ClassDB::bind_method(D_METHOD("get_lifetime_randomness"), &ParticlesMaterial::get_lifetime_randomness);
+ ClassDB::bind_method(D_METHOD("get_sub_emitter_mode"), &ParticlesMaterial::get_sub_emitter_mode);
+ ClassDB::bind_method(D_METHOD("set_sub_emitter_mode", "mode"), &ParticlesMaterial::set_sub_emitter_mode);
+
+ ClassDB::bind_method(D_METHOD("get_sub_emitter_frequency"), &ParticlesMaterial::get_sub_emitter_frequency);
+ ClassDB::bind_method(D_METHOD("set_sub_emitter_frequency", "hz"), &ParticlesMaterial::set_sub_emitter_frequency);
+
+ ClassDB::bind_method(D_METHOD("get_sub_emitter_amount_at_end"), &ParticlesMaterial::get_sub_emitter_amount_at_end);
+ ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_end", "amount"), &ParticlesMaterial::set_sub_emitter_amount_at_end);
+
+ ClassDB::bind_method(D_METHOD("get_sub_emitter_keep_velocity"), &ParticlesMaterial::get_sub_emitter_keep_velocity);
+ ClassDB::bind_method(D_METHOD("set_sub_emitter_keep_velocity", "enable"), &ParticlesMaterial::set_sub_emitter_keep_velocity);
+
ADD_GROUP("Time", "");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime_randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_lifetime_randomness", "get_lifetime_randomness");
- ADD_GROUP("Trail", "trail_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_divisor", PROPERTY_HINT_RANGE, "1,1000000,1"), "set_trail_divisor", "get_trail_divisor");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trail_size_modifier", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_trail_size_modifier", "get_trail_size_modifier");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trail_color_modifier", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_trail_color_modifier", "get_trail_color_modifier");
+
ADD_GROUP("Emission Shape", "emission_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_shape", PROPERTY_HINT_ENUM, "Point,Sphere,Box,Points,Directed Points"), "set_emission_shape", "get_emission_shape");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_sphere_radius", PROPERTY_HINT_RANGE, "0.01,128,0.01,or_greater"), "set_emission_sphere_radius", "get_emission_sphere_radius");
@@ -1186,6 +1215,12 @@ void ParticlesMaterial::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET);
+ ADD_GROUP("Sub Emitter", "sub_emitter_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_mode", PROPERTY_HINT_ENUM, "Disabled,Constant,AtEnd,AtCollision"), "set_sub_emitter_mode", "get_sub_emitter_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sub_emitter_frequency", PROPERTY_HINT_RANGE, "0.01,100,0.01"), "set_sub_emitter_frequency", "get_sub_emitter_frequency");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_amount_at_end", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_end", "get_sub_emitter_amount_at_end");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sub_emitter_keep_velocity"), "set_sub_emitter_keep_velocity", "get_sub_emitter_keep_velocity");
+
BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
BIND_ENUM_CONSTANT(PARAM_ANGULAR_VELOCITY);
BIND_ENUM_CONSTANT(PARAM_ORBIT_VELOCITY);
@@ -1233,11 +1268,15 @@ ParticlesMaterial::ParticlesMaterial() :
set_emission_shape(EMISSION_SHAPE_POINT);
set_emission_sphere_radius(1);
set_emission_box_extents(Vector3(1, 1, 1));
- set_trail_divisor(1);
set_gravity(Vector3(0, -9.8, 0));
set_lifetime_randomness(0);
emission_point_count = 1;
+ set_sub_emitter_mode(SUB_EMITTER_DISABLED);
+ set_sub_emitter_frequency(4);
+ set_sub_emitter_amount_at_end(1);
+ set_sub_emitter_keep_velocity(false);
+
for (int i = 0; i < PARAM_MAX; i++) {
set_param_randomness(Parameter(i), 0);
}
diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h
index 1c1b6c92f9..9d41c91937 100644
--- a/scene/resources/particles_material.h
+++ b/scene/resources/particles_material.h
@@ -34,6 +34,17 @@
#ifndef PARTICLES_MATERIAL_H
#define PARTICLES_MATERIAL_H
+/*
+ TODO:
+-Path following
+*Manual emission
+-Sub Emitters
+-Attractors
+-Emitter positions deformable by bones
+-Collision
+-Proper trails
+*/
+
class ParticlesMaterial : public Material {
GDCLASS(ParticlesMaterial, Material);
@@ -71,6 +82,14 @@ public:
EMISSION_SHAPE_MAX
};
+ enum SubEmitterMode {
+ SUB_EMITTER_DISABLED,
+ SUB_EMITTER_CONSTANT,
+ SUB_EMITTER_AT_END,
+ SUB_EMITTER_AT_COLLISION,
+ SUB_EMITTER_MAX
+ };
+
private:
union MaterialKey {
struct {
@@ -78,10 +97,9 @@ private:
uint32_t texture_color : 1;
uint32_t flags : 4;
uint32_t emission_shape : 2;
- uint32_t trail_size_texture : 1;
- uint32_t trail_color_texture : 1;
uint32_t invalid_key : 1;
uint32_t has_emission_color : 1;
+ uint32_t sub_emitter : 2;
};
uint32_t key;
@@ -116,9 +134,8 @@ private:
mk.texture_color = color_ramp.is_valid() ? 1 : 0;
mk.emission_shape = emission_shape;
- mk.trail_color_texture = trail_color_modifier.is_valid() ? 1 : 0;
- mk.trail_size_texture = trail_size_modifier.is_valid() ? 1 : 0;
mk.has_emission_color = emission_shape >= EMISSION_SHAPE_POINTS && emission_color_texture.is_valid();
+ mk.sub_emitter = sub_emitter_mode;
return mk;
}
@@ -178,13 +195,13 @@ private:
StringName emission_texture_normal;
StringName emission_texture_color;
- StringName trail_divisor;
- StringName trail_size_modifier;
- StringName trail_color_modifier;
-
StringName gravity;
StringName lifetime_randomness;
+
+ StringName sub_emitter_frequency;
+ StringName sub_emitter_amount_at_end;
+ StringName sub_emitter_keep_velocity;
};
static ShaderNames *shader_names;
@@ -218,15 +235,14 @@ private:
bool anim_loop;
- int trail_divisor;
-
- Ref<CurveTexture> trail_size_modifier;
- Ref<GradientTexture> trail_color_modifier;
-
Vector3 gravity;
float lifetime_randomness;
+ SubEmitterMode sub_emitter_mode;
+ float sub_emitter_frequency;
+ int sub_emitter_amount_at_end;
+ bool sub_emitter_keep_velocity;
//do not save emission points here
protected:
@@ -277,15 +293,6 @@ public:
Ref<Texture2D> get_emission_color_texture() const;
int get_emission_point_count() const;
- void set_trail_divisor(int p_divisor);
- int get_trail_divisor() const;
-
- void set_trail_size_modifier(const Ref<CurveTexture> &p_trail_size_modifier);
- Ref<CurveTexture> get_trail_size_modifier() const;
-
- void set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier);
- Ref<GradientTexture> get_trail_color_modifier() const;
-
void set_gravity(const Vector3 &p_gravity);
Vector3 get_gravity() const;
@@ -296,6 +303,18 @@ public:
static void finish_shaders();
static void flush_changes();
+ void set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode);
+ SubEmitterMode get_sub_emitter_mode() const;
+
+ void set_sub_emitter_frequency(float p_frequency);
+ float get_sub_emitter_frequency() const;
+
+ void set_sub_emitter_amount_at_end(int p_amount);
+ int get_sub_emitter_amount_at_end() const;
+
+ void set_sub_emitter_keep_velocity(bool p_enable);
+ bool get_sub_emitter_keep_velocity() const;
+
RID get_shader_rid() const;
virtual Shader::Mode get_shader_mode() const override;
@@ -307,5 +326,6 @@ public:
VARIANT_ENUM_CAST(ParticlesMaterial::Parameter)
VARIANT_ENUM_CAST(ParticlesMaterial::Flags)
VARIANT_ENUM_CAST(ParticlesMaterial::EmissionShape)
+VARIANT_ENUM_CAST(ParticlesMaterial::SubEmitterMode)
#endif // PARTICLES_MATERIAL_H
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 4249542567..92f0353abf 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -142,8 +142,6 @@ void Shader::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_param", "name"), &Shader::has_param);
- //ClassDB::bind_method(D_METHOD("get_param_list"),&Shader::get_fragment_code);
-
ADD_PROPERTY(PropertyInfo(Variant::STRING, "code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_code", "get_code");
BIND_ENUM_CONSTANT(MODE_SPATIAL);
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index eb65f10ec9..7328fbdb10 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -245,6 +245,7 @@ void StyleBoxTexture::set_region_rect(const Rect2 &p_region_rect) {
region_rect = p_region_rect;
emit_changed();
+ _change_notify("region");
}
Rect2 StyleBoxTexture::get_region_rect() const {
diff --git a/scene/resources/syntax_highlighter.cpp b/scene/resources/syntax_highlighter.cpp
index 4479b822c0..d7a08d9eb6 100644
--- a/scene/resources/syntax_highlighter.cpp
+++ b/scene/resources/syntax_highlighter.cpp
@@ -125,11 +125,11 @@ void SyntaxHighlighter::_bind_methods() {
////////////////////////////////////////////////////////////////////////////////
-static bool _is_char(CharType c) {
+static bool _is_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
}
-static bool _is_hex_symbol(CharType c) {
+static bool _is_hex_symbol(char32_t c) {
return ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
}
@@ -195,7 +195,7 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting(int p_line) {
/* search the line */
bool match = true;
- const CharType *start_key = color_regions[c].start_key.c_str();
+ const char32_t *start_key = color_regions[c].start_key.get_data();
for (int k = 0; k < start_key_length; k++) {
if (start_key[k] != str[from + k]) {
match = false;
@@ -229,18 +229,16 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting(int p_line) {
/* if we are in one find the end key */
if (in_region != -1) {
- /* check there is enough room */
- int chars_left = line_length - from;
- int end_key_length = color_regions[in_region].end_key.length();
- if (chars_left < end_key_length) {
- continue;
- }
-
/* search the line */
int region_end_index = -1;
- const CharType *end_key = color_regions[in_region].start_key.c_str();
+ int end_key_length = color_regions[in_region].end_key.length();
+ const char32_t *end_key = color_regions[in_region].end_key.get_data();
for (; from < line_length; from++) {
- if (!is_a_symbol) {
+ if (line_length - from < end_key_length) {
+ break;
+ }
+
+ if (!is_symbol(str[from])) {
continue;
}
@@ -249,9 +247,10 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting(int p_line) {
continue;
}
+ region_end_index = from;
for (int k = 0; k < end_key_length; k++) {
- if (end_key[k] == str[from + k]) {
- region_end_index = from;
+ if (end_key[k] != str[from + k]) {
+ region_end_index = -1;
break;
}
}
@@ -265,7 +264,7 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting(int p_line) {
highlighter_info["color"] = color_regions[in_region].color;
color_map[j] = highlighter_info;
- j = from;
+ j = from + (end_key_length - 1);
if (region_end_index == -1) {
color_region_cache[p_line] = in_region;
}
@@ -484,8 +483,12 @@ void CodeHighlighter::add_color_region(const String &p_start_key, const String &
}
}
+ int at = 0;
for (int i = 0; i < color_regions.size(); i++) {
ERR_FAIL_COND_MSG(color_regions[i].start_key == p_start_key, "color region with start key '" + p_start_key + "' already exists.");
+ if (p_start_key.length() < color_regions[i].start_key.length()) {
+ at++;
+ }
}
ColorRegion color_region;
@@ -493,7 +496,7 @@ void CodeHighlighter::add_color_region(const String &p_start_key, const String &
color_region.start_key = p_start_key;
color_region.end_key = p_end_key;
color_region.line_only = p_line_only || p_end_key == "";
- color_regions.push_back(color_region);
+ color_regions.insert(at, color_region);
clear_highlighting_cache();
}
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index d439d34c95..fd213859b7 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -632,11 +632,12 @@ class AnimatedTexture : public Texture2D {
//use readers writers lock for this, since its far more times read than written to
RWLock *rw_lock;
-private:
+public:
enum {
MAX_FRAMES = 256
};
+private:
RID proxy_ph;
RID proxy;
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 6992360df7..84b067d1e2 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -40,7 +40,7 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) {
if (slash == -1) {
return false;
}
- int id = String::to_int(n.c_str(), slash);
+ int id = String::to_int(n.get_data(), slash);
if (!tile_map.has(id)) {
create_tile(id);
@@ -216,7 +216,7 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const {
if (slash == -1) {
return false;
}
- int id = String::to_int(n.c_str(), slash);
+ int id = String::to_int(n.get_data(), slash);
ERR_FAIL_COND_V(!tile_map.has(id), false);
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index e4851ad9f7..b43a80c3d3 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -172,8 +172,6 @@ void VisualShaderNode::_bind_methods() {
}
VisualShaderNode::VisualShaderNode() {
- port_preview = -1;
- simple_decl = true;
}
/////////////////////////////////////////////////////////
@@ -920,7 +918,8 @@ VisualShader::RenderModeEnums VisualShader::render_mode_enums[] = {
static const char *type_string[VisualShader::TYPE_MAX] = {
"vertex",
"fragment",
- "light"
+ "light",
+ "compute"
};
bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
@@ -1367,10 +1366,19 @@ void VisualShader::_update_shader() const {
{
//fill render mode enums
int idx = 0;
+ bool specular = false;
while (render_mode_enums[idx].string) {
if (shader_mode == render_mode_enums[idx].mode) {
- if (modes.has(render_mode_enums[idx].string)) {
- int which = modes[render_mode_enums[idx].string];
+ if (shader_mode == Shader::MODE_SPATIAL) {
+ if (String(render_mode_enums[idx].string) == "specular") {
+ specular = true;
+ }
+ }
+ if (modes.has(render_mode_enums[idx].string) || specular) {
+ int which = 0;
+ if (modes.has(render_mode_enums[idx].string)) {
+ which = modes[render_mode_enums[idx].string];
+ }
int count = 0;
for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode)).size(); i++) {
String mode = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode))[i];
@@ -1406,7 +1414,7 @@ void VisualShader::_update_shader() const {
global_code += "render_mode " + render_mode + ";\n\n";
}
- static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light" };
+ static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "compute" };
String global_expressions;
Set<String> used_uniform_names;
@@ -1567,9 +1575,12 @@ void VisualShader::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_graph_offset", "get_graph_offset");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "version", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_version", "get_version");
+ ADD_PROPERTY_DEFAULT("code", ""); // Inherited from Shader, prevents showing default code as override in docs.
+
BIND_ENUM_CONSTANT(TYPE_VERTEX);
BIND_ENUM_CONSTANT(TYPE_FRAGMENT);
BIND_ENUM_CONSTANT(TYPE_LIGHT);
+ BIND_ENUM_CONSTANT(TYPE_COMPUTE);
BIND_ENUM_CONSTANT(TYPE_MAX);
BIND_CONSTANT(NODE_ID_INVALID);
@@ -1577,8 +1588,6 @@ void VisualShader::_bind_methods() {
}
VisualShader::VisualShader() {
- shader_mode = Shader::MODE_SPATIAL;
-
for (int i = 0; i < TYPE_MAX; i++) {
Ref<VisualShaderNodeOutput> output;
output.instance();
@@ -1587,8 +1596,6 @@ VisualShader::VisualShader() {
graph[i].nodes[NODE_ID_OUTPUT].node = output;
graph[i].nodes[NODE_ID_OUTPUT].position = Vector2(400, 150);
}
-
- dirty = true;
}
///////////////////////////////////////////////////////////
@@ -1711,22 +1718,20 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SAMPLER, "texture", "TEXTURE" },
- // Particles, Vertex
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
-
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" },
-
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
+ // Particles, Compute
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
// Sky, Fragment
{ Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_cubemap_pass", "AT_CUBEMAP_PASS" },
@@ -2028,10 +2033,6 @@ void VisualShaderNodeInput::_bind_methods() {
}
VisualShaderNodeInput::VisualShaderNodeInput() {
- input_name = "[None]";
- // changed when set
- shader_type = VisualShader::TYPE_MAX;
- shader_mode = Shader::MODE_MAX;
}
////////////// UniformRef
@@ -2223,8 +2224,6 @@ Vector<StringName> VisualShaderNodeUniformRef::get_editable_properties() const {
}
VisualShaderNodeUniformRef::VisualShaderNodeUniformRef() {
- uniform_name = "[None]";
- uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
}
////////////////////////////////////////////
@@ -2283,13 +2282,13 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
// Canvas Item, Light
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light", "LIGHT.rgb" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_alpha", "LIGHT.a" },
- // Particles, Vertex
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
- { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
+ // Particles, Compute
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" },
+ { Shader::MODE_PARTICLES, VisualShader::TYPE_COMPUTE, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" },
// Sky, Fragment
{ Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR" },
{ Shader::MODE_SKY, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" },
@@ -2477,7 +2476,6 @@ Vector<StringName> VisualShaderNodeUniform::get_editable_properties() const {
}
VisualShaderNodeUniform::VisualShaderNodeUniform() {
- qualifier = QUAL_NONE;
}
////////////// GroupBase
@@ -2951,10 +2949,6 @@ String VisualShaderNodeGroupBase::generate_code(Shader::Mode p_mode, VisualShade
}
VisualShaderNodeGroupBase::VisualShaderNodeGroupBase() {
- size = Size2(0, 0);
- inputs = "";
- outputs = "";
- editable = false;
simple_decl = false;
}
@@ -3079,7 +3073,6 @@ void VisualShaderNodeExpression::_bind_methods() {
}
VisualShaderNodeExpression::VisualShaderNodeExpression() {
- expression = "";
set_editable(true);
}
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 05d8950be9..8f22cb0a84 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -50,6 +50,7 @@ public:
TYPE_VERTEX,
TYPE_FRAGMENT,
TYPE_LIGHT,
+ TYPE_COMPUTE,
TYPE_MAX
};
@@ -77,7 +78,7 @@ private:
List<Connection> connections;
} graph[TYPE_MAX];
- Shader::Mode shader_mode;
+ Shader::Mode shader_mode = Shader::MODE_SPATIAL;
mutable String previous_code;
Array _get_node_connections(Type p_type) const;
@@ -94,7 +95,7 @@ private:
static RenderModeEnums render_mode_enums[];
- volatile mutable bool dirty;
+ volatile mutable bool dirty = true;
void _queue_update();
union ConnectionKey {
@@ -179,7 +180,7 @@ VARIANT_ENUM_CAST(VisualShader::Type)
class VisualShaderNode : public Resource {
GDCLASS(VisualShaderNode, Resource);
- int port_preview;
+ int port_preview = -1;
Map<int, Variant> default_input_values;
Map<int, bool> connected_input_ports;
@@ -187,7 +188,7 @@ class VisualShaderNode : public Resource {
int connected_output_count = 0;
protected:
- bool simple_decl;
+ bool simple_decl = true;
static void _bind_methods();
public:
@@ -289,8 +290,8 @@ class VisualShaderNodeInput : public VisualShaderNode {
GDCLASS(VisualShaderNodeInput, VisualShaderNode);
friend class VisualShader;
- VisualShader::Type shader_type;
- Shader::Mode shader_mode;
+ VisualShader::Type shader_type = VisualShader::TYPE_MAX;
+ Shader::Mode shader_mode = Shader::MODE_MAX;
struct Port {
Shader::Mode mode;
@@ -303,7 +304,7 @@ class VisualShaderNodeInput : public VisualShaderNode {
static const Port ports[];
static const Port preview_ports[];
- String input_name;
+ String input_name = "[None]";
protected:
static void _bind_methods();
@@ -387,8 +388,8 @@ public:
};
private:
- String uniform_name;
- Qualifier qualifier;
+ String uniform_name = "";
+ Qualifier qualifier = QUAL_NONE;
bool global_code_generated = false;
protected:
@@ -435,8 +436,8 @@ public:
};
private:
- String uniform_name;
- UniformType uniform_type;
+ String uniform_name = "[None]";
+ UniformType uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
protected:
static void _bind_methods();
@@ -478,10 +479,10 @@ private:
void _apply_port_changes();
protected:
- Vector2 size;
- String inputs;
- String outputs;
- bool editable;
+ Vector2 size = Size2(0, 0);
+ String inputs = "";
+ String outputs = "";
+ bool editable = false;
struct Port {
PortType type;
@@ -549,7 +550,7 @@ class VisualShaderNodeExpression : public VisualShaderNodeGroupBase {
GDCLASS(VisualShaderNodeExpression, VisualShaderNodeGroupBase);
protected:
- String expression;
+ String expression = "";
static void _bind_methods();
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index b0c871bc71..182aeae5d4 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -87,7 +87,6 @@ void VisualShaderNodeFloatConstant::_bind_methods() {
}
VisualShaderNodeFloatConstant::VisualShaderNodeFloatConstant() {
- constant = 0.0;
}
////////////// Scalar(Int)
@@ -147,7 +146,6 @@ void VisualShaderNodeIntConstant::_bind_methods() {
}
VisualShaderNodeIntConstant::VisualShaderNodeIntConstant() {
- constant = 0;
}
////////////// Boolean
@@ -207,7 +205,6 @@ void VisualShaderNodeBooleanConstant::_bind_methods() {
}
VisualShaderNodeBooleanConstant::VisualShaderNodeBooleanConstant() {
- constant = false;
}
////////////// Color
@@ -271,7 +268,6 @@ void VisualShaderNodeColorConstant::_bind_methods() {
}
VisualShaderNodeColorConstant::VisualShaderNodeColorConstant() {
- constant = Color(1, 1, 1, 1);
}
////////////// Vector
@@ -777,8 +773,6 @@ void VisualShaderNodeTexture::_bind_methods() {
}
VisualShaderNodeTexture::VisualShaderNodeTexture() {
- texture_type = TYPE_DATA;
- source = SOURCE_TEXTURE;
}
////////////// Sample3D
@@ -898,7 +892,6 @@ String VisualShaderNodeSample3D::get_warning(Shader::Mode p_mode, VisualShader::
}
VisualShaderNodeSample3D::VisualShaderNodeSample3D() {
- source = SOURCE_TEXTURE;
simple_decl = false;
}
@@ -1143,8 +1136,6 @@ void VisualShaderNodeCubemap::_bind_methods() {
}
VisualShaderNodeCubemap::VisualShaderNodeCubemap() {
- texture_type = TYPE_DATA;
- source = SOURCE_TEXTURE;
simple_decl = false;
}
@@ -1250,7 +1241,6 @@ void VisualShaderNodeFloatOp::_bind_methods() {
}
VisualShaderNodeFloatOp::VisualShaderNodeFloatOp() {
- op = OP_ADD;
set_input_port_default_value(0, 0.0);
set_input_port_default_value(1, 0.0);
}
@@ -1345,7 +1335,6 @@ void VisualShaderNodeIntOp::_bind_methods() {
}
VisualShaderNodeIntOp::VisualShaderNodeIntOp() {
- op = OP_ADD;
set_input_port_default_value(0, 0);
set_input_port_default_value(1, 0);
}
@@ -1460,7 +1449,6 @@ void VisualShaderNodeVectorOp::_bind_methods() {
}
VisualShaderNodeVectorOp::VisualShaderNodeVectorOp() {
- op = OP_ADD;
set_input_port_default_value(0, Vector3());
set_input_port_default_value(1, Vector3());
}
@@ -1628,7 +1616,6 @@ void VisualShaderNodeColorOp::_bind_methods() {
}
VisualShaderNodeColorOp::VisualShaderNodeColorOp() {
- op = OP_SCREEN;
set_input_port_default_value(0, Vector3());
set_input_port_default_value(1, Vector3());
}
@@ -1703,7 +1690,6 @@ void VisualShaderNodeTransformMult::_bind_methods() {
}
VisualShaderNodeTransformMult::VisualShaderNodeTransformMult() {
- op = OP_AxB;
set_input_port_default_value(0, Transform());
set_input_port_default_value(1, Transform());
}
@@ -1778,7 +1764,6 @@ void VisualShaderNodeTransformVecMult::_bind_methods() {
}
VisualShaderNodeTransformVecMult::VisualShaderNodeTransformVecMult() {
- op = OP_AxB;
set_input_port_default_value(0, Transform());
set_input_port_default_value(1, Vector3());
}
@@ -1908,7 +1893,6 @@ void VisualShaderNodeFloatFunc::_bind_methods() {
}
VisualShaderNodeFloatFunc::VisualShaderNodeFloatFunc() {
- func = FUNC_SIGN;
set_input_port_default_value(0, 0.0);
}
@@ -2003,7 +1987,6 @@ void VisualShaderNodeIntFunc::_bind_methods() {
}
VisualShaderNodeIntFunc::VisualShaderNodeIntFunc() {
- func = FUNC_SIGN;
set_input_port_default_value(0, 0);
}
@@ -2169,7 +2152,6 @@ void VisualShaderNodeVectorFunc::_bind_methods() {
}
VisualShaderNodeVectorFunc::VisualShaderNodeVectorFunc() {
- func = FUNC_NORMALIZE;
set_input_port_default_value(0, Vector3());
}
@@ -2256,9 +2238,8 @@ void VisualShaderNodeColorFunc::_bind_methods() {
}
VisualShaderNodeColorFunc::VisualShaderNodeColorFunc() {
- func = FUNC_GRAYSCALE;
- set_input_port_default_value(0, Vector3());
simple_decl = false;
+ set_input_port_default_value(0, Vector3());
}
////////////// Transform Func
@@ -2328,7 +2309,6 @@ void VisualShaderNodeTransformFunc::_bind_methods() {
}
VisualShaderNodeTransformFunc::VisualShaderNodeTransformFunc() {
- func = FUNC_INVERSE;
set_input_port_default_value(0, Transform());
}
@@ -2516,7 +2496,6 @@ void VisualShaderNodeScalarDerivativeFunc::_bind_methods() {
}
VisualShaderNodeScalarDerivativeFunc::VisualShaderNodeScalarDerivativeFunc() {
- func = FUNC_SUM;
set_input_port_default_value(0, 0.0);
}
@@ -2589,7 +2568,6 @@ void VisualShaderNodeVectorDerivativeFunc::_bind_methods() {
}
VisualShaderNodeVectorDerivativeFunc::VisualShaderNodeVectorDerivativeFunc() {
- func = FUNC_SUM;
set_input_port_default_value(0, Vector3());
}
@@ -3561,12 +3539,6 @@ Vector<StringName> VisualShaderNodeFloatUniform::get_editable_properties() const
}
VisualShaderNodeFloatUniform::VisualShaderNodeFloatUniform() {
- hint = HINT_NONE;
- hint_range_min = 0.0;
- hint_range_max = 1.0;
- hint_range_step = 0.1;
- default_value_enabled = false;
- default_value = 0.0;
}
////////////// Integer Uniform
@@ -3726,12 +3698,6 @@ Vector<StringName> VisualShaderNodeIntUniform::get_editable_properties() const {
}
VisualShaderNodeIntUniform::VisualShaderNodeIntUniform() {
- hint = HINT_NONE;
- hint_range_min = 0;
- hint_range_max = 100;
- hint_range_step = 1;
- default_value_enabled = false;
- default_value = 0;
}
////////////// Boolean Uniform
@@ -3824,8 +3790,6 @@ Vector<StringName> VisualShaderNodeBooleanUniform::get_editable_properties() con
}
VisualShaderNodeBooleanUniform::VisualShaderNodeBooleanUniform() {
- default_value_enabled = false;
- default_value = false;
}
////////////// Color Uniform
@@ -3916,8 +3880,6 @@ Vector<StringName> VisualShaderNodeColorUniform::get_editable_properties() const
}
VisualShaderNodeColorUniform::VisualShaderNodeColorUniform() {
- default_value_enabled = false;
- default_value = Color(1.0, 1.0, 1.0, 1.0);
}
////////////// Vector Uniform
@@ -4006,8 +3968,6 @@ Vector<StringName> VisualShaderNodeVec3Uniform::get_editable_properties() const
}
VisualShaderNodeVec3Uniform::VisualShaderNodeVec3Uniform() {
- default_value_enabled = false;
- default_value = Vector3(0.0, 0.0, 0.0);
}
////////////// Transform Uniform
@@ -4100,8 +4060,6 @@ Vector<StringName> VisualShaderNodeTransformUniform::get_editable_properties() c
}
VisualShaderNodeTransformUniform::VisualShaderNodeTransformUniform() {
- default_value_enabled = false;
- default_value = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0);
}
////////////// Texture Uniform
@@ -4271,8 +4229,6 @@ bool VisualShaderNodeTextureUniform::is_qualifier_supported(Qualifier p_qual) co
}
VisualShaderNodeTextureUniform::VisualShaderNodeTextureUniform() {
- texture_type = TYPE_DATA;
- color_default = COLOR_DEFAULT_WHITE;
simple_decl = false;
}
@@ -4577,13 +4533,13 @@ String VisualShaderNodeIf::generate_code(Shader::Mode p_mode, VisualShader::Type
}
VisualShaderNodeIf::VisualShaderNodeIf() {
+ simple_decl = false;
set_input_port_default_value(0, 0.0);
set_input_port_default_value(1, 0.0);
set_input_port_default_value(2, CMP_EPSILON);
set_input_port_default_value(3, Vector3(0.0, 0.0, 0.0));
set_input_port_default_value(4, Vector3(0.0, 0.0, 0.0));
set_input_port_default_value(5, Vector3(0.0, 0.0, 0.0));
- simple_decl = false;
}
////////////// Switch
@@ -4642,10 +4598,10 @@ String VisualShaderNodeSwitch::generate_code(Shader::Mode p_mode, VisualShader::
}
VisualShaderNodeSwitch::VisualShaderNodeSwitch() {
+ simple_decl = false;
set_input_port_default_value(0, false);
set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0));
set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0));
- simple_decl = false;
}
////////////// Switch(scalar)
@@ -4836,7 +4792,6 @@ void VisualShaderNodeIs::_bind_methods() {
}
VisualShaderNodeIs::VisualShaderNodeIs() {
- func = FUNC_IS_INF;
set_input_port_default_value(0, 0.0);
}
@@ -5072,9 +5027,6 @@ void VisualShaderNodeCompare::_bind_methods() {
}
VisualShaderNodeCompare::VisualShaderNodeCompare() {
- ctype = CTYPE_SCALAR;
- func = FUNC_EQUAL;
- condition = COND_ALL;
set_input_port_default_value(0, 0.0);
set_input_port_default_value(1, 0.0);
set_input_port_default_value(2, CMP_EPSILON);
@@ -5167,7 +5119,6 @@ void VisualShaderNodeMultiplyAdd::_bind_methods() {
}
VisualShaderNodeMultiplyAdd::VisualShaderNodeMultiplyAdd() {
- type = TYPE_SCALAR;
set_input_port_default_value(0, 0.0);
set_input_port_default_value(1, 0.0);
set_input_port_default_value(2, 0.0);
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index b9c40d0521..245435591b 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -39,7 +39,7 @@
class VisualShaderNodeFloatConstant : public VisualShaderNode {
GDCLASS(VisualShaderNodeFloatConstant, VisualShaderNode);
- float constant;
+ float constant = 0.0f;
protected:
static void _bind_methods();
@@ -69,7 +69,7 @@ public:
class VisualShaderNodeIntConstant : public VisualShaderNode {
GDCLASS(VisualShaderNodeIntConstant, VisualShaderNode);
- int constant;
+ int constant = 0;
protected:
static void _bind_methods();
@@ -99,7 +99,7 @@ public:
class VisualShaderNodeBooleanConstant : public VisualShaderNode {
GDCLASS(VisualShaderNodeBooleanConstant, VisualShaderNode);
- bool constant;
+ bool constant = false;
protected:
static void _bind_methods();
@@ -129,7 +129,7 @@ public:
class VisualShaderNodeColorConstant : public VisualShaderNode {
GDCLASS(VisualShaderNodeColorConstant, VisualShaderNode);
- Color constant;
+ Color constant = Color(1, 1, 1, 1);
protected:
static void _bind_methods();
@@ -240,8 +240,8 @@ public:
};
private:
- Source source;
- TextureType texture_type;
+ Source source = SOURCE_TEXTURE;
+ TextureType texture_type = TYPE_DATA;
protected:
static void _bind_methods();
@@ -294,7 +294,7 @@ public:
};
protected:
- Source source;
+ Source source = SOURCE_TEXTURE;
static void _bind_methods();
@@ -360,8 +360,8 @@ public:
};
private:
- Source source;
- TextureType texture_type;
+ Source source = SOURCE_TEXTURE;
+ TextureType texture_type = TYPE_DATA;
protected:
static void _bind_methods();
@@ -421,7 +421,7 @@ public:
};
protected:
- Operator op;
+ Operator op = OP_ADD;
static void _bind_methods();
@@ -463,7 +463,7 @@ public:
};
protected:
- Operator op;
+ Operator op = OP_ADD;
static void _bind_methods();
@@ -510,7 +510,7 @@ public:
};
protected:
- Operator op;
+ Operator op = OP_ADD;
static void _bind_methods();
@@ -556,7 +556,7 @@ public:
};
protected:
- Operator op;
+ Operator op = OP_SCREEN;
static void _bind_methods();
@@ -599,7 +599,7 @@ public:
};
protected:
- Operator op;
+ Operator op = OP_AxB;
static void _bind_methods();
@@ -642,7 +642,7 @@ public:
};
protected:
- Operator op;
+ Operator op = OP_AxB;
static void _bind_methods();
@@ -713,7 +713,7 @@ public:
};
protected:
- Function func;
+ Function func = FUNC_SIGN;
static void _bind_methods();
@@ -756,7 +756,7 @@ public:
};
protected:
- Function func;
+ Function func = FUNC_SIGN;
static void _bind_methods();
@@ -830,7 +830,7 @@ public:
};
protected:
- Function func;
+ Function func = FUNC_NORMALIZE;
static void _bind_methods();
@@ -871,7 +871,7 @@ public:
};
protected:
- Function func;
+ Function func = FUNC_GRAYSCALE;
static void _bind_methods();
@@ -912,7 +912,7 @@ public:
};
protected:
- Function func;
+ Function func = FUNC_INVERSE;
static void _bind_methods();
@@ -1067,7 +1067,7 @@ public:
};
protected:
- Function func;
+ Function func = FUNC_SUM;
static void _bind_methods();
@@ -1107,7 +1107,7 @@ public:
};
protected:
- Function func;
+ Function func = FUNC_SUM;
static void _bind_methods();
@@ -1482,12 +1482,12 @@ public:
};
private:
- Hint hint;
- float hint_range_min;
- float hint_range_max;
- float hint_range_step;
- bool default_value_enabled;
- float default_value;
+ Hint hint = HINT_NONE;
+ float hint_range_min = 0.0f;
+ float hint_range_max = 1.0f;
+ float hint_range_step = 0.1f;
+ bool default_value_enabled = false;
+ float default_value = 0.0f;
protected:
static void _bind_methods();
@@ -1544,12 +1544,12 @@ public:
};
private:
- Hint hint;
- int hint_range_min;
- int hint_range_max;
- int hint_range_step;
- bool default_value_enabled;
- int default_value;
+ Hint hint = HINT_NONE;
+ int hint_range_min = 0;
+ int hint_range_max = 100;
+ int hint_range_step = 1;
+ bool default_value_enabled = false;
+ int default_value = 0;
protected:
static void _bind_methods();
@@ -1601,8 +1601,8 @@ class VisualShaderNodeBooleanUniform : public VisualShaderNodeUniform {
GDCLASS(VisualShaderNodeBooleanUniform, VisualShaderNodeUniform);
private:
- bool default_value_enabled;
- bool default_value;
+ bool default_value_enabled = false;
+ bool default_value = false;
protected:
static void _bind_methods();
@@ -1640,8 +1640,8 @@ class VisualShaderNodeColorUniform : public VisualShaderNodeUniform {
GDCLASS(VisualShaderNodeColorUniform, VisualShaderNodeUniform);
private:
- bool default_value_enabled;
- Color default_value;
+ bool default_value_enabled = false;
+ Color default_value = Color(1.0, 1.0, 1.0, 1.0);
protected:
static void _bind_methods();
@@ -1679,7 +1679,7 @@ class VisualShaderNodeVec3Uniform : public VisualShaderNodeUniform {
GDCLASS(VisualShaderNodeVec3Uniform, VisualShaderNodeUniform);
private:
- bool default_value_enabled;
+ bool default_value_enabled = false;
Vector3 default_value;
protected:
@@ -1718,8 +1718,8 @@ class VisualShaderNodeTransformUniform : public VisualShaderNodeUniform {
GDCLASS(VisualShaderNodeTransformUniform, VisualShaderNodeUniform);
private:
- bool default_value_enabled;
- Transform default_value;
+ bool default_value_enabled = false;
+ Transform default_value = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0);
protected:
static void _bind_methods();
@@ -1770,8 +1770,8 @@ public:
};
protected:
- TextureType texture_type;
- ColorDefault color_default;
+ TextureType texture_type = TYPE_DATA;
+ ColorDefault color_default = COLOR_DEFAULT_WHITE;
protected:
static void _bind_methods();
@@ -1973,7 +1973,7 @@ public:
};
protected:
- Function func;
+ Function func = FUNC_IS_INF;
protected:
static void _bind_methods();
@@ -2032,9 +2032,9 @@ public:
};
protected:
- ComparisonType ctype;
- Function func;
- Condition condition;
+ ComparisonType ctype = CTYPE_SCALAR;
+ Function func = FUNC_EQUAL;
+ Condition condition = COND_ALL;
protected:
static void _bind_methods();
@@ -2082,7 +2082,7 @@ public:
};
protected:
- Type type;
+ Type type = TYPE_SCALAR;
protected:
static void _bind_methods();
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index 32d4e9e569..8f6d6d3b99 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -186,6 +186,10 @@ DisplayServer::WindowID DisplayServer::create_sub_window(WindowMode p_mode, uint
ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Sub-windows not supported by this display server.");
}
+void DisplayServer::show_window(WindowID p_id) {
+ ERR_FAIL_MSG("Sub-windows not supported by this display server.");
+}
+
void DisplayServer::delete_sub_window(WindowID p_id) {
ERR_FAIL_MSG("Sub-windows not supported by this display server.");
}
diff --git a/servers/display_server.h b/servers/display_server.h
index fc6520fa5e..b652418244 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -220,6 +220,7 @@ public:
};
virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
+ virtual void show_window(WindowID p_id);
virtual void delete_sub_window(WindowID p_id);
virtual WindowID get_window_at_screen_position(const Point2i &p_position) const = 0;
diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp
index 5997959432..2021aab17c 100644
--- a/servers/physics_2d/body_pair_2d_sw.cpp
+++ b/servers/physics_2d/body_pair_2d_sw.cpp
@@ -478,8 +478,8 @@ void BodyPair2DSW::solve(real_t p_step) {
Vector2 jb = c.normal * (c.acc_bias_impulse - jbnOld);
- A->apply_bias_impulse(c.rA, -jb);
- B->apply_bias_impulse(c.rB, jb);
+ A->apply_bias_impulse(-jb, c.rA);
+ B->apply_bias_impulse(jb, c.rB);
real_t jn = -(c.bounce + vn) * c.mass_normal;
real_t jnOld = c.acc_normal_impulse;
diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h
index e631046524..f609adccf9 100644
--- a/servers/physics_server_2d.h
+++ b/servers/physics_server_2d.h
@@ -644,7 +644,7 @@ class PhysicsServer2DManager {
name(p_ci.name),
create_callback(p_ci.create_callback) {}
- ClassInfo operator=(const ClassInfo &p_ci) {
+ ClassInfo &operator=(const ClassInfo &p_ci) {
name = p_ci.name;
create_callback = p_ci.create_callback;
return *this;
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index dcb183aea4..b779942460 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -785,7 +785,7 @@ class PhysicsServer3DManager {
name(p_ci.name),
create_callback(p_ci.create_callback) {}
- ClassInfo operator=(const ClassInfo &p_ci) {
+ ClassInfo &operator=(const ClassInfo &p_ci) {
name = p_ci.name;
create_callback = p_ci.create_callback;
return *this;
diff --git a/servers/rendering/rasterizer.h b/servers/rendering/rasterizer.h
index e1282fdf71..9cb611f3b4 100644
--- a/servers/rendering/rasterizer.h
+++ b/servers/rendering/rasterizer.h
@@ -86,8 +86,9 @@ public:
virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) = 0;
virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0;
+ virtual void environment_glow_set_use_high_quality(bool p_enable) = 0;
- virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_lenght, float p_detail_spread, float p_gi_inject, RS::EnvVolumetricFogShadowFilter p_shadow_filter) = 0;
+ virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, RS::EnvVolumetricFogShadowFilter p_shadow_filter) = 0;
virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0;
virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0;
@@ -660,6 +661,8 @@ public:
virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0;
virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0;
virtual void particles_restart(RID p_particles) = 0;
+ virtual void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) = 0;
+ virtual void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) = 0;
virtual bool particles_is_inactive(RID p_particles) const = 0;
@@ -677,6 +680,8 @@ public:
virtual int particles_get_draw_passes(RID p_particles) const = 0;
virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const = 0;
+ virtual void particles_set_view_axis(RID p_particles, const Vector3 &p_axis) = 0;
+
/* GLOBAL VARIABLES */
virtual void global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) = 0;
diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp
index b3279f041f..527ed09584 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp
@@ -389,7 +389,7 @@ void RasterizerEffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture,
RD::get_singleton()->compute_list_end();
}
-void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) {
+void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) {
zeromem(&copy.push_constant, sizeof(CopyPushConstant));
CopyMode copy_mode = p_first_pass && p_auto_exposure.is_valid() ? COPY_MODE_GAUSSIAN_GLOW_AUTO_EXPOSURE : COPY_MODE_GAUSSIAN_GLOW;
@@ -415,12 +415,12 @@ void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_texture,
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[copy_mode]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_back_texture), 3);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_texture), 3);
if (p_auto_exposure.is_valid() && p_first_pass) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_auto_exposure), 1);
}
- copy.push_constant.flags = base_flags | COPY_FLAG_HORIZONTAL | (p_first_pass ? COPY_FLAG_GLOW_FIRST_PASS : 0);
+ copy.push_constant.flags = base_flags | COPY_FLAG_HORIZONTAL | (p_first_pass ? COPY_FLAG_GLOW_FIRST_PASS : 0) | (p_high_quality ? COPY_FLAG_HIGH_QUALITY_GLOW : 0);
RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy.push_constant, sizeof(CopyPushConstant));
RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1);
@@ -430,8 +430,8 @@ void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_texture,
//VERTICAL
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, copy.pipelines[copy_mode]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_back_texture), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_texture), 3);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_back_texture), 3);
copy.push_constant.flags = base_flags;
RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy.push_constant, sizeof(CopyPushConstant));
@@ -1273,6 +1273,76 @@ void RasterizerEffectsRD::filter_shadow(RID p_shadow, RID p_backing_shadow, cons
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_source_rect.size.width, p_source_rect.size.height, 1, 8, 8, 1);
}
}
+
+void RasterizerEffectsRD::sort_buffer(RID p_uniform_set, int p_size) {
+ Sort::PushConstant push_constant;
+ push_constant.total_elements = p_size;
+
+ bool done = true;
+
+ int numThreadGroups = ((p_size - 1) >> 9) + 1;
+
+ if (numThreadGroups > 1) {
+ done = false;
+ }
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sort.pipelines[SORT_MODE_BLOCK]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_uniform_set, 1);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(Sort::PushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, numThreadGroups, 1, 1);
+
+ int presorted = 512;
+
+ while (!done) {
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ done = true;
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sort.pipelines[SORT_MODE_STEP]);
+
+ numThreadGroups = 0;
+
+ if (p_size > presorted) {
+ if (p_size > presorted * 2) {
+ done = false;
+ }
+
+ int pow2 = presorted;
+ while (pow2 < p_size) {
+ pow2 *= 2;
+ }
+ numThreadGroups = pow2 >> 9;
+ }
+
+ unsigned int nMergeSize = presorted * 2;
+
+ for (unsigned int nMergeSubSize = nMergeSize >> 1; nMergeSubSize > 256; nMergeSubSize = nMergeSubSize >> 1) {
+ push_constant.job_params[0] = nMergeSubSize;
+ if (nMergeSubSize == nMergeSize >> 1) {
+ push_constant.job_params[1] = (2 * nMergeSubSize - 1);
+ push_constant.job_params[2] = -1;
+ } else {
+ push_constant.job_params[1] = nMergeSubSize;
+ push_constant.job_params[2] = 1;
+ }
+ push_constant.job_params[3] = 0;
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(Sort::PushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, numThreadGroups, 1, 1);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+ }
+
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sort.pipelines[SORT_MODE_INNER]);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(Sort::PushConstant));
+ RD::get_singleton()->compute_list_dispatch(compute_list, numThreadGroups, 1, 1);
+
+ presorted *= 2;
+ }
+
+ RD::get_singleton()->compute_list_end();
+}
+
RasterizerEffectsRD::RasterizerEffectsRD() {
{ // Initialize copy
Vector<String> copy_modes;
@@ -1618,6 +1688,21 @@ RasterizerEffectsRD::RasterizerEffectsRD() {
}
}
+ {
+ Vector<String> sort_modes;
+ sort_modes.push_back("\n#define MODE_SORT_BLOCK\n");
+ sort_modes.push_back("\n#define MODE_SORT_STEP\n");
+ sort_modes.push_back("\n#define MODE_SORT_INNER\n");
+
+ sort.shader.initialize(sort_modes);
+
+ sort.shader_version = sort.shader.version_create();
+
+ for (int i = 0; i < SORT_MODE_MAX; i++) {
+ sort.pipelines[i] = RD::get_singleton()->compute_pipeline_create(sort.shader.version_get_shader(sort.shader_version, i));
+ }
+ }
+
RD::SamplerState sampler;
sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h
index b0964f23e7..e434bbc372 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h
@@ -47,6 +47,7 @@
#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/screen_space_reflection_scale.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/shadow_reduce.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/sort.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/specular_merge.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/ssao.glsl.gen.h"
#include "servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl.gen.h"
@@ -81,7 +82,8 @@ class RasterizerEffectsRD {
COPY_FLAG_GLOW_FIRST_PASS = (1 << 4),
COPY_FLAG_FLIP_Y = (1 << 5),
COPY_FLAG_FORCE_LUMINANCE = (1 << 6),
- COPY_FLAG_ALL_SOURCE = (1 << 7)
+ COPY_FLAG_ALL_SOURCE = (1 << 7),
+ COPY_FLAG_HIGH_QUALITY_GLOW = (1 << 8)
};
struct CopyPushConstant {
@@ -544,9 +546,28 @@ class RasterizerEffectsRD {
struct ShadowReduce {
ShadowReduceShaderRD shader;
RID shader_version;
- RID pipelines[2];
+ RID pipelines[SHADOW_REDUCE_MAX];
} shadow_reduce;
+ enum SortMode {
+ SORT_MODE_BLOCK,
+ SORT_MODE_STEP,
+ SORT_MODE_INNER,
+ SORT_MODE_MAX
+ };
+
+ struct Sort {
+ struct PushConstant {
+ uint32_t total_elements;
+ uint32_t pad[3];
+ int32_t job_params[4];
+ };
+
+ SortShaderRD shader;
+ RID shader_version;
+ RID pipelines[SORT_MODE_MAX];
+ } sort;
+
RID default_sampler;
RID default_mipmap_sampler;
RID index_buffer;
@@ -586,7 +607,7 @@ public:
void copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far);
void copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y = false, bool p_panorama = false);
void gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst = false);
- void gaussian_glow(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0);
+ void gaussian_glow(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0);
void cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
void make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size);
@@ -649,6 +670,8 @@ public:
void reduce_shadow(RID p_source_shadow, RID p_dest_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, int p_shrink_limit, RenderingDevice::ComputeListID compute_list);
void filter_shadow(RID p_shadow, RID p_backing_shadow, const Size2i &p_source_size, const Rect2i &p_source_rect, RS::EnvVolumetricFogShadowFilter p_filter, RenderingDevice::ComputeListID compute_list, bool p_vertical = true, bool p_horizontal = true);
+ void sort_buffer(RID p_uniform_set, int p_size);
+
RasterizerEffectsRD();
~RasterizerEffectsRD();
};
diff --git a/servers/rendering/rasterizer_rd/rasterizer_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_rd.cpp
index 18cf4fa340..509bd3ee73 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_rd.cpp
@@ -90,7 +90,7 @@ void RasterizerRD::begin_frame(double frame_step) {
void RasterizerRD::end_frame(bool p_swap_buffers) {
#ifndef _MSC_VER
-#warning TODO: likely passa bool to swap buffers to avoid display?
+#warning TODO: likely pass a bool to swap buffers to avoid display?
#endif
RD::get_singleton()->swap_buffers(); //probably should pass some bool to avoid display?
}
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
index 11abb8f4a8..efa16628e4 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp
@@ -782,8 +782,7 @@ void RasterizerSceneHighEndRD::_fill_instances(RenderList::Element **p_elements,
for (int i = 0; i < p_element_count; i++) {
const RenderList::Element *e = p_elements[i];
InstanceData &id = scene_state.instances[i];
- RasterizerStorageRD::store_transform(e->instance->transform, id.transform);
- RasterizerStorageRD::store_transform(Transform(e->instance->transform.basis.inverse().transposed()), id.normal_transform);
+ bool store_transform = true;
id.flags = 0;
id.mask = e->instance->layer_mask;
id.instance_uniforms_ofs = e->instance->instance_allocated_shader_parameters_offset >= 0 ? e->instance->instance_allocated_shader_parameters_offset : 0;
@@ -807,12 +806,42 @@ void RasterizerSceneHighEndRD::_fill_instances(RenderList::Element **p_elements,
}
id.flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT);
+ } else if (e->instance->base_type == RS::INSTANCE_PARTICLES) {
+ id.flags |= INSTANCE_DATA_FLAG_MULTIMESH;
+ uint32_t stride;
+ if (false) { // 2D particles
+ id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
+ stride = 2;
+ } else {
+ stride = 3;
+ }
+
+ id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
+ stride += 1;
+
+ id.flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
+ stride += 1;
+
+ id.flags |= (stride << INSTANCE_DATA_FLAGS_MULTIMESH_STRIDE_SHIFT);
+
+ if (!storage->particles_is_using_local_coords(e->instance->base)) {
+ store_transform = false;
+ }
+
} else if (e->instance->base_type == RS::INSTANCE_MESH) {
if (e->instance->skeleton.is_valid()) {
id.flags |= INSTANCE_DATA_FLAG_SKELETON;
}
}
+ if (store_transform) {
+ RasterizerStorageRD::store_transform(e->instance->transform, id.transform);
+ RasterizerStorageRD::store_transform(Transform(e->instance->transform.basis.inverse().transposed()), id.normal_transform);
+ } else {
+ RasterizerStorageRD::store_transform(Transform(), id.transform);
+ RasterizerStorageRD::store_transform(Transform(), id.normal_transform);
+ }
+
if (p_for_depth) {
id.gi_offset = 0xFFFFFFFF;
continue;
@@ -967,7 +996,12 @@ void RasterizerSceneHighEndRD::_render_list(RenderingDevice::DrawListID p_draw_l
ERR_CONTINUE(true); //should be a bug
} break;
case RS::INSTANCE_PARTICLES: {
- ERR_CONTINUE(true); //should be a bug
+ RID mesh = storage->particles_get_draw_pass_mesh(e->instance->base, e->surface_index >> 16);
+ ERR_CONTINUE(!mesh.is_valid()); //should be a bug
+ primitive = storage->mesh_surface_get_primitive(mesh, e->surface_index & 0xFFFF);
+
+ xforms_uniform_set = storage->particles_get_instance_buffer_uniform_set(e->instance->base, default_shader_rd, TRANSFORMS_UNIFORM_SET);
+
} break;
default: {
ERR_CONTINUE(true); //should be a bug
@@ -1036,7 +1070,9 @@ void RasterizerSceneHighEndRD::_render_list(RenderingDevice::DrawListID p_draw_l
ERR_CONTINUE(true); //should be a bug
} break;
case RS::INSTANCE_PARTICLES: {
- ERR_CONTINUE(true); //should be a bug
+ RID mesh = storage->particles_get_draw_pass_mesh(e->instance->base, e->surface_index >> 16);
+ ERR_CONTINUE(!mesh.is_valid()); //should be a bug
+ storage->mesh_surface_get_arrays_and_format(mesh, e->surface_index & 0xFFFF, pipeline->get_vertex_input_mask(), vertex_array_rd, index_array_rd, vertex_format);
} break;
default: {
ERR_CONTINUE(true); //should be a bug
@@ -1092,6 +1128,8 @@ void RasterizerSceneHighEndRD::_render_list(RenderingDevice::DrawListID p_draw_l
case RS::INSTANCE_IMMEDIATE: {
} break;
case RS::INSTANCE_PARTICLES: {
+ uint32_t instances = storage->particles_get_amount(e->instance->base);
+ RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instances);
} break;
default: {
ERR_CONTINUE(true); //should be a bug
@@ -1524,31 +1562,31 @@ void RasterizerSceneHighEndRD::_fill_render_list(InstanceBase **p_cull_result, i
_add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass);
} break;
+#endif
case RS::INSTANCE_PARTICLES: {
+ int draw_passes = storage->particles_get_draw_passes(inst->base);
- RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getornull(inst->base);
- ERR_CONTINUE(!particles);
-
- for (int j = 0; j < particles->draw_passes.size(); j++) {
-
- RID pmesh = particles->draw_passes[j];
- if (!pmesh.is_valid())
+ for (int j = 0; j < draw_passes; j++) {
+ RID mesh = storage->particles_get_draw_pass_mesh(inst->base, j);
+ if (!mesh.is_valid())
continue;
- RasterizerStorageGLES3::Mesh *mesh = storage->mesh_owner.getornull(pmesh);
- if (!mesh)
- continue; //mesh not assigned
- int ssize = mesh->surfaces.size();
+ const RID *materials = nullptr;
+ uint32_t surface_count;
- for (int k = 0; k < ssize; k++) {
+ materials = storage->mesh_get_surface_count_and_materials(mesh, surface_count);
+ if (!materials) {
+ continue; //nothing to do
+ }
- RasterizerStorageGLES3::Surface *s = mesh->surfaces[k];
- _add_geometry(s, inst, particles, -1, p_depth_pass, p_shadow_pass);
+ for (uint32_t k = 0; k < surface_count; k++) {
+ uint32_t surface_index = storage->mesh_surface_get_particles_render_pass_index(mesh, j, render_pass, &geometry_index);
+ _add_geometry(inst, (j << 16) | k, materials[j], p_pass_mode, surface_index, p_using_sdfgi);
}
}
} break;
-#endif
+
default: {
}
}
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
index 34818d2683..958d8eac1f 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp
@@ -2951,6 +2951,10 @@ void RasterizerSceneRD::environment_glow_set_use_bicubic_upscale(bool p_enable)
glow_bicubic_upscale = p_enable;
}
+void RasterizerSceneRD::environment_glow_set_use_high_quality(bool p_enable) {
+ glow_high_quality = p_enable;
+}
+
void RasterizerSceneRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, bool p_use_multibounce, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) {
Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
@@ -5265,9 +5269,9 @@ void RasterizerSceneRD::_render_buffers_post_process_and_tonemap(RID p_render_bu
if (env->auto_exposure && rb->luminance.current.is_valid()) {
luminance_texture = rb->luminance.current;
}
- storage->get_effects()->gaussian_glow(rb->texture, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale);
+ storage->get_effects()->gaussian_glow(rb->texture, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale);
} else {
- storage->get_effects()->gaussian_glow(rb->blur[1].mipmaps[i - 1].texture, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength);
+ storage->get_effects()->gaussian_glow(rb->blur[1].mipmaps[i - 1].texture, rb->blur[0].mipmaps[i + 1].texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality);
}
}
}
@@ -8310,6 +8314,7 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) {
screen_space_roughness_limiter_amount = GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_amount");
screen_space_roughness_limiter_limit = GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_limit");
glow_bicubic_upscale = int(GLOBAL_GET("rendering/quality/glow/upscale_mode")) > 0;
+ glow_high_quality = GLOBAL_GET("rendering/quality/glow/use_high_quality");
ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/quality/screen_space_reflection/roughness_quality")));
sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_quality")));
sss_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_scale");
diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
index f504240f50..fe31d2f76b 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h
@@ -359,7 +359,7 @@ private:
mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner;
- /* REFLECTION PROBE INSTANCE */
+ /* DECAL INSTANCE */
struct DecalInstance {
RID decal;
@@ -765,6 +765,7 @@ private:
RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM;
bool ssao_half_size = false;
bool glow_bicubic_upscale = false;
+ bool glow_high_quality = false;
RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGNESS_QUALITY_LOW;
static uint64_t auto_exposure_counter;
@@ -1530,6 +1531,7 @@ public:
void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap);
void environment_glow_set_use_bicubic_upscale(bool p_enable);
+ void environment_glow_set_use_high_quality(bool p_enable);
void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density);
bool environment_is_fog_enabled(RID p_env) const;
@@ -1540,7 +1542,7 @@ public:
float environment_get_fog_height(RID p_env) const;
float environment_get_fog_height_density(RID p_env) const;
- void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_lenght, float p_detail_spread, float p_gi_inject, RS::EnvVolumetricFogShadowFilter p_shadow_filter);
+ void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, RS::EnvVolumetricFogShadowFilter p_shadow_filter);
virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth);
virtual void environment_set_volumetric_fog_filter_active(bool p_enable);
diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
index f3ba57e733..d751f474cd 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
+++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.cpp
@@ -33,6 +33,7 @@
#include "core/engine.h"
#include "core/io/resource_loader.h"
#include "core/project_settings.h"
+#include "rasterizer_rd.h"
#include "servers/rendering/shader_language.h"
Ref<Image> RasterizerStorageRD::_validate_texture_format(const Ref<Image> &p_image, TextureToRDFormat &r_format) {
@@ -3098,8 +3099,914 @@ void RasterizerStorageRD::_update_dirty_multimeshes() {
multimesh_dirty_list = nullptr;
}
-/* SKELETON */
+/* PARTICLES */
+RID RasterizerStorageRD::particles_create() {
+ return particles_owner.make_rid(Particles());
+}
+
+void RasterizerStorageRD::particles_set_emitting(RID p_particles, bool p_emitting) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->emitting = p_emitting;
+}
+
+bool RasterizerStorageRD::particles_get_emitting(RID p_particles) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND_V(!particles, false);
+
+ return particles->emitting;
+}
+
+void RasterizerStorageRD::_particles_free_data(Particles *particles) {
+ if (!particles->particle_buffer.is_valid()) {
+ return;
+ }
+ RD::get_singleton()->free(particles->particle_buffer);
+ RD::get_singleton()->free(particles->frame_params_buffer);
+ RD::get_singleton()->free(particles->particle_instance_buffer);
+ particles->particles_transforms_buffer_uniform_set = RID();
+ particles->particle_buffer = RID();
+
+ if (particles->particles_sort_buffer.is_valid()) {
+ RD::get_singleton()->free(particles->particles_sort_buffer);
+ particles->particles_sort_buffer = RID();
+ }
+
+ if (particles->emission_buffer != nullptr) {
+ particles->emission_buffer = nullptr;
+ particles->emission_buffer_data.clear();
+ RD::get_singleton()->free(particles->emission_storage_buffer);
+ particles->emission_storage_buffer = RID();
+ }
+}
+
+void RasterizerStorageRD::particles_set_amount(RID p_particles, int p_amount) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ if (particles->amount == p_amount) {
+ return;
+ }
+
+ _particles_free_data(particles);
+
+ particles->amount = p_amount;
+
+ if (particles->amount > 0) {
+ particles->particle_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticleData) * p_amount);
+ particles->frame_params_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticlesFrameParams) * 1);
+ particles->particle_instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * 4 * (3 + 1 + 1) * p_amount);
+ //needs to clear it
+
+ {
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 1;
+ u.ids.push_back(particles->particle_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 2;
+ u.ids.push_back(particles->particle_instance_buffer);
+ uniforms.push_back(u);
+ }
+
+ particles->particles_copy_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, 0), 0);
+ }
+ }
+
+ particles->prev_ticks = 0;
+ particles->phase = 0;
+ particles->prev_phase = 0;
+ particles->clear = true;
+}
+
+void RasterizerStorageRD::particles_set_lifetime(RID p_particles, float p_lifetime) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+ particles->lifetime = p_lifetime;
+}
+
+void RasterizerStorageRD::particles_set_one_shot(RID p_particles, bool p_one_shot) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+ particles->one_shot = p_one_shot;
+}
+
+void RasterizerStorageRD::particles_set_pre_process_time(RID p_particles, float p_time) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+ particles->pre_process_time = p_time;
+}
+void RasterizerStorageRD::particles_set_explosiveness_ratio(RID p_particles, float p_ratio) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+ particles->explosiveness = p_ratio;
+}
+void RasterizerStorageRD::particles_set_randomness_ratio(RID p_particles, float p_ratio) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+ particles->randomness = p_ratio;
+}
+
+void RasterizerStorageRD::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+ particles->custom_aabb = p_aabb;
+ particles->instance_dependency.instance_notify_changed(true, false);
+}
+
+void RasterizerStorageRD::particles_set_speed_scale(RID p_particles, float p_scale) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->speed_scale = p_scale;
+}
+void RasterizerStorageRD::particles_set_use_local_coordinates(RID p_particles, bool p_enable) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->use_local_coords = p_enable;
+}
+
+void RasterizerStorageRD::particles_set_fixed_fps(RID p_particles, int p_fps) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->fixed_fps = p_fps;
+}
+
+void RasterizerStorageRD::particles_set_fractional_delta(RID p_particles, bool p_enable) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->fractional_delta = p_enable;
+}
+
+void RasterizerStorageRD::particles_set_process_material(RID p_particles, RID p_material) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->process_material = p_material;
+}
+
+void RasterizerStorageRD::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->draw_order = p_order;
+}
+
+void RasterizerStorageRD::particles_set_draw_passes(RID p_particles, int p_passes) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->draw_passes.resize(p_passes);
+}
+
+void RasterizerStorageRD::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+ ERR_FAIL_INDEX(p_pass, particles->draw_passes.size());
+ particles->draw_passes.write[p_pass] = p_mesh;
+}
+
+void RasterizerStorageRD::particles_restart(RID p_particles) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->restart_request = true;
+}
+
+void RasterizerStorageRD::_particles_allocate_emission_buffer(Particles *particles) {
+ ERR_FAIL_COND(particles->emission_buffer != nullptr);
+
+ particles->emission_buffer_data.resize(sizeof(ParticleEmissionBuffer::Data) * particles->amount + sizeof(uint32_t) * 4);
+ zeromem(particles->emission_buffer_data.ptrw(), particles->emission_buffer_data.size());
+ particles->emission_buffer = (ParticleEmissionBuffer *)particles->emission_buffer_data.ptrw();
+ particles->emission_buffer->particle_max = particles->amount;
+
+ particles->emission_storage_buffer = RD::get_singleton()->storage_buffer_create(particles->emission_buffer_data.size(), particles->emission_buffer_data);
+
+ if (RD::get_singleton()->uniform_set_is_valid(particles->particles_material_uniform_set)) {
+ //will need to be re-created
+ RD::get_singleton()->free(particles->particles_material_uniform_set);
+ particles->particles_material_uniform_set = RID();
+ }
+}
+
+void RasterizerStorageRD::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+ ERR_FAIL_COND(p_particles == p_subemitter_particles);
+
+ particles->sub_emitter = p_subemitter_particles;
+
+ if (RD::get_singleton()->uniform_set_is_valid(particles->particles_material_uniform_set)) {
+ RD::get_singleton()->free(particles->particles_material_uniform_set);
+ particles->particles_material_uniform_set = RID(); //clear and force to re create sub emitting
+ }
+}
+
+void RasterizerStorageRD::particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+ ERR_FAIL_COND(particles->amount == 0);
+
+ if (particles->emitting) {
+ particles->clear = true;
+ particles->emitting = false;
+ }
+
+ if (particles->emission_buffer == nullptr) {
+ _particles_allocate_emission_buffer(particles);
+ }
+
+ if (particles->inactive) {
+ //in case it was inactive, make active again
+ particles->inactive = false;
+ particles->inactive_time = 0;
+ }
+
+ int32_t idx = particles->emission_buffer->particle_count;
+ if (idx < particles->emission_buffer->particle_max) {
+ store_transform(p_transform, particles->emission_buffer->data[idx].xform);
+
+ particles->emission_buffer->data[idx].velocity[0] = p_velocity.x;
+ particles->emission_buffer->data[idx].velocity[1] = p_velocity.y;
+ particles->emission_buffer->data[idx].velocity[2] = p_velocity.z;
+
+ particles->emission_buffer->data[idx].custom[0] = p_custom.r;
+ particles->emission_buffer->data[idx].custom[1] = p_custom.g;
+ particles->emission_buffer->data[idx].custom[2] = p_custom.b;
+ particles->emission_buffer->data[idx].custom[3] = p_custom.a;
+
+ particles->emission_buffer->data[idx].color[0] = p_color.r;
+ particles->emission_buffer->data[idx].color[1] = p_color.g;
+ particles->emission_buffer->data[idx].color[2] = p_color.b;
+ particles->emission_buffer->data[idx].color[3] = p_color.a;
+
+ particles->emission_buffer->data[idx].flags = p_emit_flags;
+ particles->emission_buffer->particle_count++;
+ }
+}
+
+void RasterizerStorageRD::particles_request_process(RID p_particles) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ if (!particles->dirty) {
+ particles->dirty = true;
+ particles->update_list = particle_update_list;
+ particle_update_list = particles;
+ }
+}
+
+AABB RasterizerStorageRD::particles_get_current_aabb(RID p_particles) {
+ const Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND_V(!particles, AABB());
+
+ Vector<ParticleData> data;
+ data.resize(particles->amount);
+
+ Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(particles->particle_buffer);
+
+ Transform inv = particles->emission_transform.affine_inverse();
+
+ AABB aabb;
+ if (buffer.size()) {
+ bool first = true;
+ const ParticleData *particle_data = (const ParticleData *)data.ptr();
+ for (int i = 0; i < particles->amount; i++) {
+ if (particle_data[i].active) {
+ Vector3 pos = Vector3(particle_data[i].xform[12], particle_data[i].xform[13], particle_data[i].xform[14]);
+ if (!particles->use_local_coords) {
+ pos = inv.xform(pos);
+ }
+ if (first) {
+ aabb.position = pos;
+ first = false;
+ } else {
+ aabb.expand_to(pos);
+ }
+ }
+ }
+ }
+
+ float longest_axis_size = 0;
+ for (int i = 0; i < particles->draw_passes.size(); i++) {
+ if (particles->draw_passes[i].is_valid()) {
+ AABB maabb = mesh_get_aabb(particles->draw_passes[i], RID());
+ longest_axis_size = MAX(maabb.get_longest_axis_size(), longest_axis_size);
+ }
+ }
+
+ aabb.grow_by(longest_axis_size);
+
+ return aabb;
+}
+
+AABB RasterizerStorageRD::particles_get_aabb(RID p_particles) const {
+ const Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND_V(!particles, AABB());
+
+ return particles->custom_aabb;
+}
+
+void RasterizerStorageRD::particles_set_emission_transform(RID p_particles, const Transform &p_transform) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ particles->emission_transform = p_transform;
+}
+
+int RasterizerStorageRD::particles_get_draw_passes(RID p_particles) const {
+ const Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND_V(!particles, 0);
+
+ return particles->draw_passes.size();
+}
+
+RID RasterizerStorageRD::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const {
+ const Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND_V(!particles, RID());
+ ERR_FAIL_INDEX_V(p_pass, particles->draw_passes.size(), RID());
+
+ return particles->draw_passes[p_pass];
+}
+
+void RasterizerStorageRD::_particles_process(Particles *p_particles, float p_delta) {
+ if (p_particles->particles_material_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(p_particles->particles_material_uniform_set)) {
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(p_particles->frame_params_buffer);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 1;
+ u.ids.push_back(p_particles->particle_buffer);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 2;
+ if (p_particles->emission_storage_buffer.is_valid()) {
+ u.ids.push_back(p_particles->emission_storage_buffer);
+ } else {
+ u.ids.push_back(default_rd_storage_buffer);
+ }
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 3;
+ Particles *sub_emitter = particles_owner.getornull(p_particles->sub_emitter);
+ if (sub_emitter) {
+ if (sub_emitter->emission_buffer == nullptr) { //no emission buffer, allocate emission buffer
+ _particles_allocate_emission_buffer(sub_emitter);
+ }
+ u.ids.push_back(sub_emitter->emission_storage_buffer);
+ } else {
+ u.ids.push_back(default_rd_storage_buffer);
+ }
+ uniforms.push_back(u);
+ }
+
+ p_particles->particles_material_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.default_shader_rd, 1);
+ }
+
+ float new_phase = Math::fmod((float)p_particles->phase + (p_delta / p_particles->lifetime) * p_particles->speed_scale, (float)1.0);
+
+ ParticlesFrameParams &frame_params = p_particles->frame_params;
+
+ if (p_particles->clear) {
+ p_particles->cycle_number = 0;
+ p_particles->random_seed = Math::rand();
+ } else if (new_phase < p_particles->phase) {
+ if (p_particles->one_shot) {
+ p_particles->emitting = false;
+ }
+ p_particles->cycle_number++;
+ }
+
+ frame_params.emitting = p_particles->emitting;
+ frame_params.system_phase = new_phase;
+ frame_params.prev_system_phase = p_particles->phase;
+
+ p_particles->phase = new_phase;
+
+ frame_params.time = RasterizerRD::singleton->get_total_time();
+ frame_params.delta = p_delta * p_particles->speed_scale;
+ frame_params.random_seed = p_particles->random_seed;
+ frame_params.explosiveness = p_particles->explosiveness;
+ frame_params.randomness = p_particles->randomness;
+
+ if (p_particles->use_local_coords) {
+ store_transform(Transform(), frame_params.emission_transform);
+ } else {
+ store_transform(p_particles->emission_transform, frame_params.emission_transform);
+ }
+
+ frame_params.cycle = p_particles->cycle_number;
+
+ ParticlesShader::PushConstant push_constant;
+
+ push_constant.clear = p_particles->clear;
+ push_constant.total_particles = p_particles->amount;
+ push_constant.lifetime = p_particles->lifetime;
+ push_constant.trail_size = 1;
+ push_constant.use_fractional_delta = p_particles->fractional_delta;
+ push_constant.sub_emitter_mode = !p_particles->emitting && p_particles->emission_buffer && (p_particles->emission_buffer->particle_count > 0 || p_particles->force_sub_emit);
+
+ p_particles->force_sub_emit = false; //reset
+
+ Particles *sub_emitter = particles_owner.getornull(p_particles->sub_emitter);
+
+ if (sub_emitter && sub_emitter->emission_storage_buffer.is_valid()) {
+ // print_line("updating subemitter buffer");
+ int32_t zero[4] = { 0, sub_emitter->amount, 0, 0 };
+ RD::get_singleton()->buffer_update(sub_emitter->emission_storage_buffer, 0, sizeof(uint32_t) * 4, zero, true);
+ push_constant.can_emit = true;
+
+ if (sub_emitter->emitting) {
+ sub_emitter->emitting = false;
+ sub_emitter->clear = true; //will need to clear if it was emitting, sorry
+ }
+ //make sure the sub emitter processes particles too
+ sub_emitter->inactive = false;
+ sub_emitter->inactive_time = 0;
+
+ sub_emitter->force_sub_emit = true;
+
+ } else {
+ push_constant.can_emit = false;
+ }
+
+ if (p_particles->emission_buffer && p_particles->emission_buffer->particle_count) {
+ RD::get_singleton()->buffer_update(p_particles->emission_storage_buffer, 0, sizeof(uint32_t) * 4 + sizeof(ParticleEmissionBuffer::Data) * p_particles->emission_buffer->particle_count, p_particles->emission_buffer, true);
+ p_particles->emission_buffer->particle_count = 0;
+ }
+
+ p_particles->clear = false;
+
+ RD::get_singleton()->buffer_update(p_particles->frame_params_buffer, 0, sizeof(ParticlesFrameParams), &frame_params, true);
+
+ ParticlesMaterialData *m = (ParticlesMaterialData *)material_get_data(p_particles->process_material, SHADER_TYPE_PARTICLES);
+ if (!m) {
+ m = (ParticlesMaterialData *)material_get_data(particles_shader.default_material, SHADER_TYPE_PARTICLES);
+ }
+
+ ERR_FAIL_COND(!m);
+
+ //todo should maybe compute all particle systems together?
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, m->shader_data->pipeline);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles_shader.base_uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, p_particles->particles_material_uniform_set, 1);
+ if (m->uniform_set.is_valid()) {
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, m->uniform_set, 2);
+ }
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ParticlesShader::PushConstant));
+
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_particles->amount, 1, 1, 64, 1, 1);
+
+ RD::get_singleton()->compute_list_end();
+}
+
+void RasterizerStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &p_axis) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND(!particles);
+
+ if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH) {
+ return; //uninteresting for other modes
+ }
+
+ //copy to sort buffer
+ if (particles->particles_sort_buffer == RID()) {
+ uint32_t size = particles->amount;
+ if (size & 1) {
+ size++; //make multiple of 16
+ }
+ size *= sizeof(float) * 2;
+ particles->particles_sort_buffer = RD::get_singleton()->storage_buffer_create(size);
+ {
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(particles->particles_sort_buffer);
+ uniforms.push_back(u);
+ }
+
+ particles->particles_sort_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, ParticlesShader::COPY_MODE_FILL_SORT_BUFFER), 1);
+ }
+ }
+
+ Vector3 axis = -p_axis; // cameras look to z negative
+
+ if (particles->use_local_coords) {
+ axis = particles->emission_transform.basis.xform_inv(axis).normalized();
+ }
+
+ ParticlesShader::CopyPushConstant copy_push_constant;
+ copy_push_constant.total_particles = particles->amount;
+ copy_push_constant.sort_direction[0] = axis.x;
+ copy_push_constant.sort_direction[1] = axis.y;
+ copy_push_constant.sort_direction[2] = axis.z;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_SORT_BUFFER]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy_push_constant, sizeof(ParticlesShader::CopyPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1, 64, 1, 1);
+
+ RD::get_singleton()->compute_list_end();
+
+ effects.sort_buffer(particles->particles_sort_uniform_set, particles->amount);
+
+ compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy_push_constant, sizeof(ParticlesShader::CopyPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1, 64, 1, 1);
+
+ RD::get_singleton()->compute_list_end();
+}
+
+void RasterizerStorageRD::update_particles() {
+ while (particle_update_list) {
+ //use transform feedback to process particles
+
+ Particles *particles = particle_update_list;
+
+ //take and remove
+ particle_update_list = particles->update_list;
+ particles->update_list = nullptr;
+ particles->dirty = false;
+
+ if (particles->restart_request) {
+ particles->prev_ticks = 0;
+ particles->phase = 0;
+ particles->prev_phase = 0;
+ particles->clear = true;
+ particles->restart_request = false;
+ }
+
+ if (particles->inactive && !particles->emitting) {
+ //go next
+ continue;
+ }
+
+ if (particles->emitting) {
+ if (particles->inactive) {
+ //restart system from scratch
+ particles->prev_ticks = 0;
+ particles->phase = 0;
+ particles->prev_phase = 0;
+ particles->clear = true;
+ }
+ particles->inactive = false;
+ particles->inactive_time = 0;
+ } else {
+ particles->inactive_time += particles->speed_scale * RasterizerRD::singleton->get_frame_delta_time();
+ if (particles->inactive_time > particles->lifetime * 1.2) {
+ particles->inactive = true;
+ continue;
+ }
+ }
+
+ bool zero_time_scale = Engine::get_singleton()->get_time_scale() <= 0.0;
+
+ if (particles->clear && particles->pre_process_time > 0.0) {
+ float frame_time;
+ if (particles->fixed_fps > 0)
+ frame_time = 1.0 / particles->fixed_fps;
+ else
+ frame_time = 1.0 / 30.0;
+
+ float todo = particles->pre_process_time;
+
+ while (todo >= 0) {
+ _particles_process(particles, frame_time);
+ todo -= frame_time;
+ }
+ }
+
+ if (particles->fixed_fps > 0) {
+ float frame_time;
+ float decr;
+ if (zero_time_scale) {
+ frame_time = 0.0;
+ decr = 1.0 / particles->fixed_fps;
+ } else {
+ frame_time = 1.0 / particles->fixed_fps;
+ decr = frame_time;
+ }
+ float delta = RasterizerRD::singleton->get_frame_delta_time();
+ if (delta > 0.1) { //avoid recursive stalls if fps goes below 10
+ delta = 0.1;
+ } else if (delta <= 0.0) { //unlikely but..
+ delta = 0.001;
+ }
+ float todo = particles->frame_remainder + delta;
+
+ while (todo >= frame_time) {
+ _particles_process(particles, frame_time);
+ todo -= decr;
+ }
+
+ particles->frame_remainder = todo;
+
+ } else {
+ if (zero_time_scale)
+ _particles_process(particles, 0.0);
+ else
+ _particles_process(particles, RasterizerRD::singleton->get_frame_delta_time());
+ }
+
+ //copy particles to instance buffer
+
+ if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH) {
+ ParticlesShader::CopyPushConstant copy_push_constant;
+ copy_push_constant.total_particles = particles->amount;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_INSTANCES]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0);
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &copy_push_constant, sizeof(ParticlesShader::CopyPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1, 64, 1, 1);
+
+ RD::get_singleton()->compute_list_end();
+ }
+
+ particles->instance_dependency.instance_notify_changed(true, false); //make sure shadows are updated
+ }
+}
+
+bool RasterizerStorageRD::particles_is_inactive(RID p_particles) const {
+ const Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND_V(!particles, false);
+ return !particles->emitting && particles->inactive;
+}
+
+/* SKY SHADER */
+
+void RasterizerStorageRD::ParticlesShaderData::set_code(const String &p_code) {
+ //compile
+
+ code = p_code;
+ valid = false;
+ ubo_size = 0;
+ uniforms.clear();
+
+ if (code == String()) {
+ return; //just invalid, but no error
+ }
+
+ ShaderCompilerRD::GeneratedCode gen_code;
+ ShaderCompilerRD::IdentifierActions actions;
+
+ /*
+ uses_time = false;
+
+ actions.render_mode_flags["use_half_res_pass"] = &uses_half_res;
+ actions.render_mode_flags["use_quarter_res_pass"] = &uses_quarter_res;
+
+ actions.usage_flag_pointers["TIME"] = &uses_time;
+*/
+
+ actions.uniforms = &uniforms;
+
+ Error err = base_singleton->particles_shader.compiler.compile(RS::SHADER_PARTICLES, code, &actions, path, gen_code);
+
+ ERR_FAIL_COND(err != OK);
+
+ if (version.is_null()) {
+ version = base_singleton->particles_shader.shader.version_create();
+ }
+
+ base_singleton->particles_shader.shader.version_set_compute_code(version, gen_code.uniforms, gen_code.compute_global, gen_code.compute, gen_code.defines);
+ ERR_FAIL_COND(!base_singleton->particles_shader.shader.version_is_valid(version));
+
+ ubo_size = gen_code.uniform_total_size;
+ ubo_offsets = gen_code.uniform_offsets;
+ texture_uniforms = gen_code.texture_uniforms;
+
+ //update pipelines
+
+ pipeline = RD::get_singleton()->compute_pipeline_create(base_singleton->particles_shader.shader.version_get_shader(version, 0));
+
+ valid = true;
+}
+
+void RasterizerStorageRD::ParticlesShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) {
+ if (!p_texture.is_valid()) {
+ default_texture_params.erase(p_name);
+ } else {
+ default_texture_params[p_name] = p_texture;
+ }
+}
+
+void RasterizerStorageRD::ParticlesShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+ Map<int, StringName> order;
+
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+ if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ if (E->get().texture_order >= 0) {
+ order[E->get().texture_order + 100000] = E->key();
+ } else {
+ order[E->get().order] = E->key();
+ }
+ }
+
+ for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) {
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]);
+ pi.name = E->get();
+ p_param_list->push_back(pi);
+ }
+}
+
+void RasterizerStorageRD::ParticlesShaderData::get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const {
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+ if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ RasterizerStorage::InstanceShaderParam p;
+ p.info = ShaderLanguage::uniform_to_property_info(E->get());
+ p.info.name = E->key(); //supply name
+ p.index = E->get().instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint);
+ p_param_list->push_back(p);
+ }
+}
+
+bool RasterizerStorageRD::ParticlesShaderData::is_param_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
+ }
+
+ return uniforms[p_param].texture_order >= 0;
+}
+
+bool RasterizerStorageRD::ParticlesShaderData::is_animated() const {
+ return false;
+}
+
+bool RasterizerStorageRD::ParticlesShaderData::casts_shadows() const {
+ return false;
+}
+
+Variant RasterizerStorageRD::ParticlesShaderData::get_default_parameter(const StringName &p_parameter) const {
+ if (uniforms.has(p_parameter)) {
+ ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
+ Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
+ }
+ return Variant();
+}
+
+RasterizerStorageRD::ParticlesShaderData::ParticlesShaderData() {
+ valid = false;
+}
+
+RasterizerStorageRD::ParticlesShaderData::~ParticlesShaderData() {
+ //pipeline variants will clear themselves if shader is gone
+ if (version.is_valid()) {
+ base_singleton->particles_shader.shader.version_free(version);
+ }
+}
+
+RasterizerStorageRD::ShaderData *RasterizerStorageRD::_create_particles_shader_func() {
+ ParticlesShaderData *shader_data = memnew(ParticlesShaderData);
+ return shader_data;
+}
+
+void RasterizerStorageRD::ParticlesMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+ uniform_set_updated = true;
+
+ if ((uint32_t)ubo_data.size() != shader_data->ubo_size) {
+ p_uniform_dirty = true;
+ if (uniform_buffer.is_valid()) {
+ RD::get_singleton()->free(uniform_buffer);
+ uniform_buffer = RID();
+ }
+
+ ubo_data.resize(shader_data->ubo_size);
+ if (ubo_data.size()) {
+ uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size());
+ memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear
+ }
+
+ //clear previous uniform set
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ uniform_set = RID();
+ }
+ }
+
+ //check whether buffer changed
+ if (p_uniform_dirty && ubo_data.size()) {
+ update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false);
+ RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw());
+ }
+
+ uint32_t tex_uniform_count = shader_data->texture_uniforms.size();
+
+ if ((uint32_t)texture_cache.size() != tex_uniform_count) {
+ texture_cache.resize(tex_uniform_count);
+ p_textures_dirty = true;
+
+ //clear previous uniform set
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ uniform_set = RID();
+ }
+ }
+
+ if (p_textures_dirty && tex_uniform_count) {
+ update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true);
+ }
+
+ if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) {
+ // This material does not require an uniform set, so don't create it.
+ return;
+ }
+
+ if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ //no reason to update uniform set, only UBO (or nothing) was needed to update
+ return;
+ }
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ if (shader_data->ubo_size) {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(uniform_buffer);
+ uniforms.push_back(u);
+ }
+
+ const RID *textures = texture_cache.ptrw();
+ for (uint32_t i = 0; i < tex_uniform_count; i++) {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 1 + i;
+ u.ids.push_back(textures[i]);
+ uniforms.push_back(u);
+ }
+ }
+
+ uniform_set = RD::get_singleton()->uniform_set_create(uniforms, base_singleton->particles_shader.shader.version_get_shader(shader_data->version, 0), 2);
+}
+
+RasterizerStorageRD::ParticlesMaterialData::~ParticlesMaterialData() {
+ if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+ RD::get_singleton()->free(uniform_set);
+ }
+
+ if (uniform_buffer.is_valid()) {
+ RD::get_singleton()->free(uniform_buffer);
+ }
+}
+
+RasterizerStorageRD::MaterialData *RasterizerStorageRD::_create_particles_material_func(ParticlesShaderData *p_shader) {
+ ParticlesMaterialData *material_data = memnew(ParticlesMaterialData);
+ material_data->shader_data = p_shader;
+ material_data->last_frame = false;
+ //update will happen later anyway so do nothing.
+ return material_data;
+}
+////////
/* SKELETON API */
RID RasterizerStorageRD::skeleton_create() {
@@ -4683,6 +5590,9 @@ void RasterizerStorageRD::base_update_dependency(RID p_base, RasterizerScene::In
} else if (light_owner.owns(p_base)) {
Light *l = light_owner.getornull(p_base);
p_instance->update_dependency(&l->instance_dependency);
+ } else if (particles_owner.owns(p_base)) {
+ Particles *p = particles_owner.getornull(p_base);
+ p_instance->update_dependency(&p->instance_dependency);
}
}
@@ -4715,6 +5625,9 @@ RS::InstanceType RasterizerStorageRD::get_base_type(RID p_rid) const {
if (lightmap_owner.owns(p_rid)) {
return RS::INSTANCE_LIGHTMAP;
}
+ if (particles_owner.owns(p_rid)) {
+ return RS::INSTANCE_PARTICLES;
+ }
return RS::INSTANCE_NONE;
}
@@ -5618,6 +6531,8 @@ void RasterizerStorageRD::update_dirty_resources() {
_update_dirty_multimeshes();
_update_dirty_skeletons();
_update_decal_atlas();
+
+ update_particles();
}
bool RasterizerStorageRD::has_os_feature(const String &p_feature) const {
@@ -5747,6 +6662,11 @@ bool RasterizerStorageRD::free(RID p_rid) {
light->instance_dependency.instance_notify_deleted(p_rid);
light_owner.free(p_rid);
+ } else if (particles_owner.owns(p_rid)) {
+ Particles *particles = particles_owner.getornull(p_rid);
+ _particles_free_data(particles);
+ particles->instance_dependency.instance_notify_deleted(p_rid);
+ particles_owner.free(p_rid);
} else if (render_target_owner.owns(p_rid)) {
RenderTarget *rt = render_target_owner.getornull(p_rid);
@@ -6211,6 +7131,125 @@ RasterizerStorageRD::RasterizerStorageRD() {
}
lightmap_probe_capture_update_speed = GLOBAL_GET("rendering/lightmapper/probe_capture_update_speed");
+
+ /* Particles */
+
+ {
+ // Initialize particles
+ Vector<String> particles_modes;
+ particles_modes.push_back("");
+ particles_shader.shader.initialize(particles_modes, String());
+ }
+ shader_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_PARTICLES, _create_particles_shader_funcs);
+ material_set_data_request_function(RasterizerStorageRD::SHADER_TYPE_PARTICLES, _create_particles_material_funcs);
+
+ {
+ ShaderCompilerRD::DefaultIdentifierActions actions;
+
+ actions.renames["COLOR"] = "PARTICLE.color";
+ actions.renames["VELOCITY"] = "PARTICLE.velocity";
+ //actions.renames["MASS"] = "mass"; ?
+ actions.renames["ACTIVE"] = "PARTICLE.is_active";
+ actions.renames["RESTART"] = "restart";
+ actions.renames["CUSTOM"] = "PARTICLE.custom";
+ actions.renames["TRANSFORM"] = "PARTICLE.xform";
+ actions.renames["TIME"] = "FRAME.time";
+ actions.renames["LIFETIME"] = "params.lifetime";
+ actions.renames["DELTA"] = "local_delta";
+ actions.renames["NUMBER"] = "particle";
+ actions.renames["INDEX"] = "index";
+ //actions.renames["GRAVITY"] = "current_gravity";
+ actions.renames["EMISSION_TRANSFORM"] = "FRAME.emission_transform";
+ actions.renames["RANDOM_SEED"] = "FRAME.random_seed";
+ actions.renames["FLAG_EMIT_POSITION"] = "EMISSION_FLAG_HAS_POSITION";
+ actions.renames["FLAG_EMIT_ROT_SCALE"] = "EMISSION_FLAG_HAS_ROTATION_SCALE";
+ actions.renames["FLAG_EMIT_VELOCITY"] = "EMISSION_FLAG_HAS_VELOCITY";
+ actions.renames["FLAG_EMIT_COLOR"] = "EMISSION_FLAG_HAS_COLOR";
+ actions.renames["FLAG_EMIT_CUSTOM"] = "EMISSION_FLAG_HAS_CUSTOM";
+ actions.renames["RESTART_POSITION"] = "restart_position";
+ actions.renames["RESTART_ROT_SCALE"] = "restart_rotation_scale";
+ actions.renames["RESTART_VELOCITY"] = "restart_velocity";
+ actions.renames["RESTART_COLOR"] = "restart_color";
+ actions.renames["RESTART_CUSTOM"] = "restart_custom";
+ actions.renames["emit_particle"] = "emit_particle";
+
+ actions.render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n";
+ actions.render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n";
+ actions.render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n";
+
+ actions.sampler_array_name = "material_samplers";
+ actions.base_texture_binding_index = 1;
+ actions.texture_layout_set = 2;
+ actions.base_uniform_string = "material.";
+ actions.base_varying_index = 10;
+
+ actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
+ actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
+ actions.global_buffer_array_variable = "global_variables.data";
+
+ particles_shader.compiler.initialize(actions);
+ }
+
+ {
+ // default material and shader for particles shader
+ particles_shader.default_shader = shader_create();
+ shader_set_code(particles_shader.default_shader, "shader_type particles; void compute() { COLOR = vec4(1.0); } \n");
+ particles_shader.default_material = material_create();
+ material_set_shader(particles_shader.default_material, particles_shader.default_shader);
+
+ ParticlesMaterialData *md = (ParticlesMaterialData *)material_get_data(particles_shader.default_material, RasterizerStorageRD::SHADER_TYPE_PARTICLES);
+ particles_shader.default_shader_rd = particles_shader.shader.version_get_shader(md->shader_data->version, 0);
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_SAMPLER;
+ u.binding = 1;
+ u.ids.resize(12);
+ RID *ids_ptr = u.ids.ptrw();
+ ids_ptr[0] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[1] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[2] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[3] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[4] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[5] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[6] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[7] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[8] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[9] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[10] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[11] = sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ uniforms.push_back(u);
+ }
+
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 2;
+ u.ids.push_back(global_variables_get_storage_buffer());
+ uniforms.push_back(u);
+ }
+
+ particles_shader.base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.default_shader_rd, 0);
+ }
+
+ default_rd_storage_buffer = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t) * 4);
+
+ {
+ Vector<String> copy_modes;
+ copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n");
+ copy_modes.push_back("\n#define MODE_FILL_SORT_BUFFER\n#define USE_SORT_BUFFER\n");
+ copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n#define USE_SORT_BUFFER\n");
+
+ particles_shader.copy_shader.initialize(copy_modes);
+
+ particles_shader.copy_shader_version = particles_shader.copy_shader.version_create();
+
+ for (int i = 0; i < ParticlesShader::COPY_MODE_MAX; i++) {
+ particles_shader.copy_pipelines[i] = RD::get_singleton()->compute_pipeline_create(particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, i));
+ }
+ }
}
RasterizerStorageRD::~RasterizerStorageRD() {
@@ -6237,6 +7276,8 @@ RasterizerStorageRD::~RasterizerStorageRD() {
}
giprobe_sdf_shader.version_free(giprobe_sdf_shader_version);
+ RD::get_singleton()->free(default_rd_storage_buffer);
+
if (decal_atlas.textures.size()) {
ERR_PRINT("Decal Atlas: " + itos(decal_atlas.textures.size()) + " textures were not removed from the atlas.");
}
diff --git a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
index 6e5923953b..cecae6bbb2 100644
--- a/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
+++ b/servers/rendering/rasterizer_rd/rasterizer_storage_rd.h
@@ -36,6 +36,8 @@
#include "servers/rendering/rasterizer_rd/rasterizer_effects_rd.h"
#include "servers/rendering/rasterizer_rd/shader_compiler_rd.h"
#include "servers/rendering/rasterizer_rd/shaders/giprobe_sdf.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/particles.glsl.gen.h"
+#include "servers/rendering/rasterizer_rd/shaders/particles_copy.glsl.gen.h"
#include "servers/rendering/rendering_device.h"
class RasterizerStorageRD : public RasterizerStorage {
@@ -247,6 +249,7 @@ private:
RID default_rd_textures[DEFAULT_RD_TEXTURE_MAX];
RID default_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
+ RID default_rd_storage_buffer;
/* DECAL ATLAS */
@@ -386,6 +389,9 @@ private:
uint32_t multimesh_render_index = 0;
uint64_t multimesh_render_pass = 0;
+
+ uint32_t particles_render_index = 0;
+ uint64_t particles_render_pass = 0;
};
uint32_t blend_shape_count = 0;
@@ -448,6 +454,248 @@ private:
_FORCE_INLINE_ void _multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances);
void _update_dirty_multimeshes();
+ /* PARTICLES */
+
+ struct ParticleData {
+ float xform[16];
+ float velocity[3];
+ uint32_t active;
+ float color[4];
+ float custom[3];
+ float lifetime;
+ uint32_t pad[3];
+ };
+
+ struct ParticlesFrameParams {
+ uint32_t emitting;
+ float system_phase;
+ float prev_system_phase;
+ uint32_t cycle;
+
+ float explosiveness;
+ float randomness;
+ float time;
+ float delta;
+
+ uint32_t random_seed;
+ uint32_t pad[3];
+
+ float emission_transform[16];
+ };
+
+ struct ParticleEmissionBufferData {
+ };
+
+ struct ParticleEmissionBuffer {
+ struct Data {
+ float xform[16];
+ float velocity[3];
+ uint32_t flags;
+ float color[4];
+ float custom[4];
+ };
+
+ int32_t particle_count;
+ int32_t particle_max;
+ uint32_t pad1;
+ uint32_t pad2;
+ Data data[1]; //its 2020 and empty arrays are still non standard in C++
+ };
+
+ struct Particles {
+ bool inactive;
+ float inactive_time;
+ bool emitting;
+ bool one_shot;
+ int amount;
+ float lifetime;
+ float pre_process_time;
+ float explosiveness;
+ float randomness;
+ bool restart_request;
+ AABB custom_aabb;
+ bool use_local_coords;
+ RID process_material;
+
+ RS::ParticlesDrawOrder draw_order;
+
+ Vector<RID> draw_passes;
+
+ RID particle_buffer;
+ RID particle_instance_buffer;
+ RID frame_params_buffer;
+
+ RID particles_material_uniform_set;
+ RID particles_copy_uniform_set;
+ RID particles_transforms_buffer_uniform_set;
+
+ RID particles_sort_buffer;
+ RID particles_sort_uniform_set;
+
+ bool dirty = false;
+ Particles *update_list = nullptr;
+
+ RID sub_emitter;
+
+ float phase;
+ float prev_phase;
+ uint64_t prev_ticks;
+ uint32_t random_seed;
+
+ uint32_t cycle_number;
+
+ float speed_scale;
+
+ int fixed_fps;
+ bool fractional_delta;
+ float frame_remainder;
+
+ bool clear;
+
+ bool force_sub_emit = false;
+
+ Transform emission_transform;
+
+ Vector<uint8_t> emission_buffer_data;
+
+ ParticleEmissionBuffer *emission_buffer = nullptr;
+ RID emission_storage_buffer;
+
+ Particles() :
+ inactive(true),
+ inactive_time(0.0),
+ emitting(false),
+ one_shot(false),
+ amount(0),
+ lifetime(1.0),
+ pre_process_time(0.0),
+ explosiveness(0.0),
+ randomness(0.0),
+ restart_request(false),
+ custom_aabb(AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8))),
+ use_local_coords(true),
+ draw_order(RS::PARTICLES_DRAW_ORDER_INDEX),
+ prev_ticks(0),
+ random_seed(0),
+ cycle_number(0),
+ speed_scale(1.0),
+ fixed_fps(0),
+ fractional_delta(false),
+ frame_remainder(0),
+ clear(true) {
+ }
+
+ RasterizerScene::InstanceDependency instance_dependency;
+
+ ParticlesFrameParams frame_params;
+ };
+
+ void _particles_process(Particles *p_particles, float p_delta);
+ void _particles_allocate_emission_buffer(Particles *particles);
+ void _particles_free_data(Particles *particles);
+
+ struct ParticlesShader {
+ struct PushConstant {
+ float lifetime;
+ uint32_t clear;
+ uint32_t total_particles;
+ uint32_t trail_size;
+
+ uint32_t use_fractional_delta;
+ uint32_t sub_emitter_mode;
+ uint32_t can_emit;
+ uint32_t pad;
+ };
+
+ ParticlesShaderRD shader;
+ ShaderCompilerRD compiler;
+
+ RID default_shader;
+ RID default_material;
+ RID default_shader_rd;
+
+ RID base_uniform_set;
+
+ struct CopyPushConstant {
+ float sort_direction[3];
+ uint32_t total_particles;
+ };
+
+ enum {
+ COPY_MODE_FILL_INSTANCES,
+ COPY_MODE_FILL_SORT_BUFFER,
+ COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER,
+ COPY_MODE_MAX,
+ };
+
+ ParticlesCopyShaderRD copy_shader;
+ RID copy_shader_version;
+ RID copy_pipelines[COPY_MODE_MAX];
+
+ } particles_shader;
+
+ Particles *particle_update_list = nullptr;
+
+ struct ParticlesShaderData : public ShaderData {
+ bool valid;
+ RID version;
+
+ //RenderPipelineVertexFormatCacheRD pipelines[SKY_VERSION_MAX];
+ Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+ Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms;
+
+ Vector<uint32_t> ubo_offsets;
+ uint32_t ubo_size;
+
+ String path;
+ String code;
+ Map<StringName, RID> default_texture_params;
+
+ RID pipeline;
+
+ bool uses_time;
+
+ virtual void set_code(const String &p_Code);
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture);
+ virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_instance_param_list(List<RasterizerStorage::InstanceShaderParam> *p_param_list) const;
+ virtual bool is_param_texture(const StringName &p_param) const;
+ virtual bool is_animated() const;
+ virtual bool casts_shadows() const;
+ virtual Variant get_default_parameter(const StringName &p_parameter) const;
+ ParticlesShaderData();
+ virtual ~ParticlesShaderData();
+ };
+
+ ShaderData *_create_particles_shader_func();
+ static RasterizerStorageRD::ShaderData *_create_particles_shader_funcs() {
+ return base_singleton->_create_particles_shader_func();
+ }
+
+ struct ParticlesMaterialData : public MaterialData {
+ uint64_t last_frame;
+ ParticlesShaderData *shader_data;
+ RID uniform_buffer;
+ RID uniform_set;
+ Vector<RID> texture_cache;
+ Vector<uint8_t> ubo_data;
+ bool uniform_set_updated;
+
+ virtual void set_render_priority(int p_priority) {}
+ virtual void set_next_pass(RID p_pass) {}
+ virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+ virtual ~ParticlesMaterialData();
+ };
+
+ MaterialData *_create_particles_material_func(ParticlesShaderData *p_shader);
+ static RasterizerStorageRD::MaterialData *_create_particles_material_funcs(ShaderData *p_shader) {
+ return base_singleton->_create_particles_material_func(static_cast<ParticlesShaderData *>(p_shader));
+ }
+
+ void update_particles();
+
+ mutable RID_Owner<Particles> particles_owner;
+
/* Skeleton */
struct Skeleton {
@@ -977,6 +1225,19 @@ public:
return s->multimesh_render_index;
}
+ _FORCE_INLINE_ uint32_t mesh_surface_get_particles_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ Mesh::Surface *s = mesh->surfaces[p_surface_index];
+
+ if (s->particles_render_pass != p_render_pass) {
+ (*r_index)++;
+ s->particles_render_pass = p_render_pass;
+ s->particles_render_index = *r_index;
+ }
+
+ return s->particles_render_index;
+ }
+
/* MULTIMESH API */
RID multimesh_create();
@@ -1407,39 +1668,77 @@ public:
/* PARTICLES */
- RID particles_create() { return RID(); }
+ RID particles_create();
+
+ void particles_set_emitting(RID p_particles, bool p_emitting);
+ void particles_set_amount(RID p_particles, int p_amount);
+ void particles_set_lifetime(RID p_particles, float p_lifetime);
+ void particles_set_one_shot(RID p_particles, bool p_one_shot);
+ void particles_set_pre_process_time(RID p_particles, float p_time);
+ void particles_set_explosiveness_ratio(RID p_particles, float p_ratio);
+ void particles_set_randomness_ratio(RID p_particles, float p_ratio);
+ void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb);
+ void particles_set_speed_scale(RID p_particles, float p_scale);
+ void particles_set_use_local_coordinates(RID p_particles, bool p_enable);
+ void particles_set_process_material(RID p_particles, RID p_material);
+ void particles_set_fixed_fps(RID p_particles, int p_fps);
+ void particles_set_fractional_delta(RID p_particles, bool p_enable);
+ void particles_restart(RID p_particles);
+ void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags);
+ void particles_set_subemitter(RID p_particles, RID p_subemitter_particles);
+
+ void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order);
+
+ void particles_set_draw_passes(RID p_particles, int p_count);
+ void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh);
+
+ void particles_request_process(RID p_particles);
+ AABB particles_get_current_aabb(RID p_particles);
+ AABB particles_get_aabb(RID p_particles) const;
+
+ void particles_set_emission_transform(RID p_particles, const Transform &p_transform);
- void particles_set_emitting(RID p_particles, bool p_emitting) {}
- void particles_set_amount(RID p_particles, int p_amount) {}
- void particles_set_lifetime(RID p_particles, float p_lifetime) {}
- void particles_set_one_shot(RID p_particles, bool p_one_shot) {}
- void particles_set_pre_process_time(RID p_particles, float p_time) {}
- void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) {}
- void particles_set_randomness_ratio(RID p_particles, float p_ratio) {}
- void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) {}
- void particles_set_speed_scale(RID p_particles, float p_scale) {}
- void particles_set_use_local_coordinates(RID p_particles, bool p_enable) {}
- void particles_set_process_material(RID p_particles, RID p_material) {}
- void particles_set_fixed_fps(RID p_particles, int p_fps) {}
- void particles_set_fractional_delta(RID p_particles, bool p_enable) {}
- void particles_restart(RID p_particles) {}
+ bool particles_get_emitting(RID p_particles);
+ int particles_get_draw_passes(RID p_particles) const;
+ RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const;
- void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) {}
+ void particles_set_view_axis(RID p_particles, const Vector3 &p_axis);
- void particles_set_draw_passes(RID p_particles, int p_count) {}
- void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) {}
+ virtual bool particles_is_inactive(RID p_particles) const;
- void particles_request_process(RID p_particles) {}
- AABB particles_get_current_aabb(RID p_particles) { return AABB(); }
- AABB particles_get_aabb(RID p_particles) const { return AABB(); }
+ _FORCE_INLINE_ uint32_t particles_get_amount(RID p_particles) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND_V(!particles, 0);
- void particles_set_emission_transform(RID p_particles, const Transform &p_transform) {}
+ return particles->amount;
+ }
+
+ _FORCE_INLINE_ uint32_t particles_is_using_local_coords(RID p_particles) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND_V(!particles, false);
+
+ return particles->use_local_coords;
+ }
+
+ _FORCE_INLINE_ RID particles_get_instance_buffer_uniform_set(RID p_particles, RID p_shader, uint32_t p_set) {
+ Particles *particles = particles_owner.getornull(p_particles);
+ ERR_FAIL_COND_V(!particles, RID());
+ if (particles->particles_transforms_buffer_uniform_set.is_null()) {
+ Vector<RD::Uniform> uniforms;
- bool particles_get_emitting(RID p_particles) { return false; }
- int particles_get_draw_passes(RID p_particles) const { return 0; }
- RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const { return RID(); }
+ {
+ RD::Uniform u;
+ u.type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 0;
+ u.ids.push_back(particles->particle_instance_buffer);
+ uniforms.push_back(u);
+ }
- virtual bool particles_is_inactive(RID p_particles) const { return false; }
+ particles->particles_transforms_buffer_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_set);
+ }
+
+ return particles->particles_transforms_buffer_uniform_set;
+ }
/* GLOBAL VARIABLES API */
diff --git a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp b/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp
index 1820c39c5a..f70ddbb75a 100644
--- a/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp
+++ b/servers/rendering/rasterizer_rd/shader_compiler_rd.cpp
@@ -537,6 +537,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
r_gen_code.vertex_global += struct_code;
r_gen_code.fragment_global += struct_code;
+ r_gen_code.compute_global += struct_code;
}
int max_texture_uniforms = 0;
@@ -591,6 +592,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
if (SL::is_sampler_type(E->get().type)) {
r_gen_code.vertex_global += ucode;
r_gen_code.fragment_global += ucode;
+ r_gen_code.compute_global += ucode;
GeneratedCode::Texture texture;
texture.name = E->key();
@@ -700,6 +702,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
vcode += ";\n";
r_gen_code.vertex_global += "layout(location=" + itos(index) + ") " + interp_mode + "out " + vcode;
r_gen_code.fragment_global += "layout(location=" + itos(index) + ") " + interp_mode + "in " + vcode;
+ r_gen_code.compute_global += "layout(location=" + itos(index) + ") " + interp_mode + "out " + vcode;
index++;
}
@@ -724,6 +727,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
gcode += ";\n";
r_gen_code.vertex_global += gcode;
r_gen_code.fragment_global += gcode;
+ r_gen_code.compute_global += gcode;
}
Map<StringName, String> function_code;
@@ -741,6 +745,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
Set<StringName> added_vtx;
Set<StringName> added_fragment; //share for light
+ Set<StringName> added_compute; //share for light
for (int i = 0; i < pnode->functions.size(); i++) {
SL::FunctionNode *fnode = pnode->functions[i].function;
@@ -763,6 +768,12 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
_dump_function_deps(pnode, fnode->name, function_code, r_gen_code.fragment_global, added_fragment);
r_gen_code.light = function_code[light_name];
}
+
+ if (fnode->name == compute_name) {
+ _dump_function_deps(pnode, fnode->name, function_code, r_gen_code.compute_global, added_compute);
+ r_gen_code.compute = function_code[compute_name];
+ }
+
function = nullptr;
}
@@ -1245,6 +1256,8 @@ Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, Ide
r_gen_code.vertex_global = String();
r_gen_code.fragment = String();
r_gen_code.fragment_global = String();
+ r_gen_code.compute = String();
+ r_gen_code.compute_global = String();
r_gen_code.light = String();
r_gen_code.uses_fragment_time = false;
r_gen_code.uses_vertex_time = false;
@@ -1266,6 +1279,7 @@ void ShaderCompilerRD::initialize(DefaultIdentifierActions p_actions) {
vertex_name = "vertex";
fragment_name = "fragment";
+ compute_name = "compute";
light_name = "light";
time_name = "TIME";
diff --git a/servers/rendering/rasterizer_rd/shader_compiler_rd.h b/servers/rendering/rasterizer_rd/shader_compiler_rd.h
index ce94fb743f..565520ec65 100644
--- a/servers/rendering/rasterizer_rd/shader_compiler_rd.h
+++ b/servers/rendering/rasterizer_rd/shader_compiler_rd.h
@@ -68,6 +68,8 @@ public:
String fragment_global;
String fragment;
String light;
+ String compute_global;
+ String compute;
bool uses_global_textures;
bool uses_fragment_time;
@@ -104,6 +106,7 @@ private:
StringName vertex_name;
StringName fragment_name;
StringName light_name;
+ StringName compute_name;
StringName time_name;
Set<StringName> texture_functions;
diff --git a/servers/rendering/rasterizer_rd/shaders/SCsub b/servers/rendering/rasterizer_rd/shaders/SCsub
index 3aa863be98..9d531d63ad 100644
--- a/servers/rendering/rasterizer_rd/shaders/SCsub
+++ b/servers/rendering/rasterizer_rd/shaders/SCsub
@@ -37,3 +37,6 @@ if "RD_GLSL" in env["BUILDERS"]:
env.RD_GLSL("sdfgi_debug_probes.glsl")
env.RD_GLSL("volumetric_fog.glsl")
env.RD_GLSL("shadow_reduce.glsl")
+ env.RD_GLSL("particles.glsl")
+ env.RD_GLSL("particles_copy.glsl")
+ env.RD_GLSL("sort.glsl")
diff --git a/servers/rendering/rasterizer_rd/shaders/copy.glsl b/servers/rendering/rasterizer_rd/shaders/copy.glsl
index eb39c28fa9..e565bd8e3d 100644
--- a/servers/rendering/rasterizer_rd/shaders/copy.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/copy.glsl
@@ -14,6 +14,7 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
#define FLAG_FLIP_Y (1 << 5)
#define FLAG_FORCE_LUMINANCE (1 << 6)
#define FLAG_COPY_ALL_SOURCE (1 << 7)
+#define FLAG_HIGH_QUALITY_GLOW (1 << 8)
layout(push_constant, binding = 1, std430) uniform Params {
ivec4 section;
@@ -116,17 +117,42 @@ void main() {
vec4 color = vec4(0.0);
if (bool(params.flags & FLAG_HORIZONTAL)) {
- ivec2 base_pos = (pos + params.section.xy) << 1;
+ ivec2 base_pos = ((pos + params.section.xy) << 1) + ivec2(1);
ivec2 section_begin = params.section.xy << 1;
ivec2 section_end = section_begin + (params.section.zw << 1);
- GLOW_ADD(ivec2(0, 0), 0.174938);
- GLOW_ADD(ivec2(1, 0), 0.165569);
- GLOW_ADD(ivec2(2, 0), 0.140367);
- GLOW_ADD(ivec2(3, 0), 0.106595);
- GLOW_ADD(ivec2(-1, 0), 0.165569);
- GLOW_ADD(ivec2(-2, 0), 0.140367);
- GLOW_ADD(ivec2(-3, 0), 0.106595);
+ if (bool(params.flags & FLAG_HIGH_QUALITY_GLOW)) {
+ //Sample from two lines to capture single pixel features
+ GLOW_ADD(ivec2(0, 0), 0.152781);
+ GLOW_ADD(ivec2(1, 0), 0.144599);
+ GLOW_ADD(ivec2(2, 0), 0.122589);
+ GLOW_ADD(ivec2(3, 0), 0.093095);
+ GLOW_ADD(ivec2(4, 0), 0.063327);
+ GLOW_ADD(ivec2(-1, 0), 0.144599);
+ GLOW_ADD(ivec2(-2, 0), 0.122589);
+ GLOW_ADD(ivec2(-3, 0), 0.093095);
+ GLOW_ADD(ivec2(-4, 0), 0.063327);
+
+ GLOW_ADD(ivec2(0, 1), 0.152781);
+ GLOW_ADD(ivec2(1, 1), 0.144599);
+ GLOW_ADD(ivec2(2, 1), 0.122589);
+ GLOW_ADD(ivec2(3, 1), 0.093095);
+ GLOW_ADD(ivec2(4, 1), 0.063327);
+ GLOW_ADD(ivec2(-1, 1), 0.144599);
+ GLOW_ADD(ivec2(-2, 1), 0.122589);
+ GLOW_ADD(ivec2(-3, 1), 0.093095);
+ GLOW_ADD(ivec2(-4, 1), 0.063327);
+ color *= 0.5;
+ } else {
+ GLOW_ADD(ivec2(0, 0), 0.174938);
+ GLOW_ADD(ivec2(1, 0), 0.165569);
+ GLOW_ADD(ivec2(2, 0), 0.140367);
+ GLOW_ADD(ivec2(3, 0), 0.106595);
+ GLOW_ADD(ivec2(-1, 0), 0.165569);
+ GLOW_ADD(ivec2(-2, 0), 0.140367);
+ GLOW_ADD(ivec2(-3, 0), 0.106595);
+ }
+
color *= params.glow_strength;
} else {
ivec2 base_pos = pos + params.section.xy;
diff --git a/servers/rendering/rasterizer_rd/shaders/particles.glsl b/servers/rendering/rasterizer_rd/shaders/particles.glsl
new file mode 100644
index 0000000000..3de807b57c
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/particles.glsl
@@ -0,0 +1,394 @@
+#[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
+
+#define SAMPLER_NEAREST_CLAMP 0
+#define SAMPLER_LINEAR_CLAMP 1
+#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2
+#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3
+#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4
+#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5
+#define SAMPLER_NEAREST_REPEAT 6
+#define SAMPLER_LINEAR_REPEAT 7
+#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8
+#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9
+#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10
+#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11
+
+/* SET 0: GLOBAL DATA */
+
+layout(set = 0, binding = 1) uniform sampler material_samplers[12];
+
+layout(set = 0, binding = 2, std430) restrict readonly buffer GlobalVariableData {
+ vec4 data[];
+}
+global_variables;
+
+/* Set 1: FRAME AND PARTICLE DATA */
+
+// a frame history is kept for trail deterministic behavior
+struct FrameParams {
+ bool emitting;
+ float system_phase;
+ float prev_system_phase;
+ uint cycle;
+
+ float explosiveness;
+ float randomness;
+ float time;
+ float delta;
+
+ uint random_seed;
+ uint pad[3];
+
+ mat4 emission_transform;
+};
+
+layout(set = 1, binding = 0, std430) restrict buffer FrameHistory {
+ FrameParams data[];
+}
+frame_history;
+
+struct ParticleData {
+ mat4 xform;
+ vec3 velocity;
+ bool is_active;
+ vec4 color;
+ vec4 custom;
+};
+
+layout(set = 1, binding = 1, std430) restrict buffer Particles {
+ ParticleData data[];
+}
+particles;
+
+#define EMISSION_FLAG_HAS_POSITION 1
+#define EMISSION_FLAG_HAS_ROTATION_SCALE 2
+#define EMISSION_FLAG_HAS_VELOCITY 4
+#define EMISSION_FLAG_HAS_COLOR 8
+#define EMISSION_FLAG_HAS_CUSTOM 16
+
+struct ParticleEmission {
+ mat4 xform;
+ vec3 velocity;
+ uint flags;
+ vec4 color;
+ vec4 custom;
+};
+
+layout(set = 1, binding = 2, std430) restrict volatile coherent buffer SourceEmission {
+ int particle_count;
+ uint pad0;
+ uint pad1;
+ uint pad2;
+ ParticleEmission data[];
+}
+src_particles;
+
+layout(set = 1, binding = 3, std430) restrict volatile coherent buffer DestEmission {
+ int particle_count;
+ int particle_max;
+ uint pad1;
+ uint pad2;
+ ParticleEmission data[];
+}
+dst_particles;
+
+/* SET 2: MATERIAL */
+
+#ifdef USE_MATERIAL_UNIFORMS
+layout(set = 2, binding = 0, std140) uniform MaterialUniforms{
+ /* clang-format off */
+MATERIAL_UNIFORMS
+ /* clang-format on */
+} material;
+#endif
+
+layout(push_constant, binding = 0, std430) uniform Params {
+ float lifetime;
+ bool clear;
+ uint total_particles;
+ uint trail_size;
+ bool use_fractional_delta;
+ bool sub_emitter_mode;
+ bool can_emit;
+ uint pad;
+}
+params;
+
+uint hash(uint x) {
+ x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
+ x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
+ x = (x >> uint(16)) ^ x;
+ return x;
+}
+
+bool emit_particle(mat4 p_xform, vec3 p_velocity, vec4 p_color, vec4 p_custom, uint p_flags) {
+ if (!params.can_emit) {
+ return false;
+ }
+
+ bool valid = false;
+
+ int dst_index = atomicAdd(dst_particles.particle_count, 1);
+
+ if (dst_index >= dst_particles.particle_max) {
+ atomicAdd(dst_particles.particle_count, -1);
+ return false;
+ }
+ /*
+ valid = true;
+
+ int attempts = 256; // never trust compute
+ while(attempts-- > 0) {
+ dst_index = dst_particles.particle_count;
+ if (dst_index == dst_particles.particle_max) {
+ return false; //cant emit anymore
+ }
+
+ if (atomicCompSwap(dst_particles.particle_count, dst_index, dst_index +1 ) != dst_index) {
+ continue;
+ }
+ valid=true;
+ break;
+ }
+
+ barrier();
+
+ if (!valid) {
+ return false; //gave up (attempts exhausted)
+ }
+*/
+ dst_particles.data[dst_index].xform = p_xform;
+ dst_particles.data[dst_index].velocity = p_velocity;
+ dst_particles.data[dst_index].color = p_color;
+ dst_particles.data[dst_index].custom = p_custom;
+ dst_particles.data[dst_index].flags = p_flags;
+
+ return true;
+}
+
+/* clang-format off */
+
+COMPUTE_SHADER_GLOBALS
+
+/* clang-format on */
+
+void main() {
+ uint particle = gl_GlobalInvocationID.x;
+
+ if (particle >= params.total_particles * params.trail_size) {
+ return; //discard
+ }
+
+ uint index = particle / params.trail_size;
+ uint frame = (particle % params.trail_size);
+
+#define FRAME frame_history.data[frame]
+#define PARTICLE particles.data[particle]
+
+ bool apply_forces = true;
+ bool apply_velocity = true;
+ float local_delta = FRAME.delta;
+
+ float mass = 1.0;
+
+ bool restart = false;
+
+ bool restart_position = false;
+ bool restart_rotation_scale = false;
+ bool restart_velocity = false;
+ bool restart_color = false;
+ bool restart_custom = false;
+
+ if (params.clear) {
+ PARTICLE.color = vec4(1.0);
+ PARTICLE.custom = vec4(0.0);
+ PARTICLE.velocity = vec3(0.0);
+ PARTICLE.is_active = false;
+ PARTICLE.xform = mat4(
+ vec4(1.0, 0.0, 0.0, 0.0),
+ vec4(0.0, 1.0, 0.0, 0.0),
+ vec4(0.0, 0.0, 1.0, 0.0),
+ vec4(0.0, 0.0, 0.0, 1.0));
+ }
+
+ if (params.sub_emitter_mode) {
+ if (!PARTICLE.is_active) {
+ int src_index = atomicAdd(src_particles.particle_count, -1) - 1;
+
+ if (src_index >= 0) {
+ PARTICLE.is_active = true;
+ restart = true;
+
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_POSITION)) {
+ PARTICLE.xform[3] = src_particles.data[src_index].xform[3];
+ } else {
+ PARTICLE.xform[3] = vec4(0, 0, 0, 1);
+ restart_position = true;
+ }
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_ROTATION_SCALE)) {
+ PARTICLE.xform[0] = src_particles.data[src_index].xform[0];
+ PARTICLE.xform[1] = src_particles.data[src_index].xform[1];
+ PARTICLE.xform[2] = src_particles.data[src_index].xform[2];
+ } else {
+ PARTICLE.xform[0] = vec4(1, 0, 0, 0);
+ PARTICLE.xform[1] = vec4(0, 1, 0, 0);
+ PARTICLE.xform[2] = vec4(0, 0, 1, 0);
+ restart_rotation_scale = true;
+ }
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_VELOCITY)) {
+ PARTICLE.velocity = src_particles.data[src_index].velocity;
+ } else {
+ PARTICLE.velocity = vec3(0);
+ restart_velocity = true;
+ }
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_COLOR)) {
+ PARTICLE.color = src_particles.data[src_index].color;
+ } else {
+ PARTICLE.color = vec4(1);
+ restart_color = true;
+ }
+
+ if (bool(src_particles.data[src_index].flags & EMISSION_FLAG_HAS_CUSTOM)) {
+ PARTICLE.custom = src_particles.data[src_index].custom;
+ } else {
+ PARTICLE.custom = vec4(0);
+ restart_custom = true;
+ }
+ }
+ }
+
+ } else if (FRAME.emitting) {
+ float restart_phase = float(index) / float(params.total_particles);
+
+ if (FRAME.randomness > 0.0) {
+ uint seed = FRAME.cycle;
+ if (restart_phase >= FRAME.system_phase) {
+ seed -= uint(1);
+ }
+ seed *= uint(params.total_particles);
+ seed += uint(index);
+ float random = float(hash(seed) % uint(65536)) / 65536.0;
+ restart_phase += FRAME.randomness * random * 1.0 / float(params.total_particles);
+ }
+
+ restart_phase *= (1.0 - FRAME.explosiveness);
+
+ if (FRAME.system_phase > FRAME.prev_system_phase) {
+ // restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed
+
+ if (restart_phase >= FRAME.prev_system_phase && restart_phase < FRAME.system_phase) {
+ restart = true;
+ if (params.use_fractional_delta) {
+ local_delta = (FRAME.system_phase - restart_phase) * params.lifetime;
+ }
+ }
+
+ } else if (FRAME.delta > 0.0) {
+ if (restart_phase >= FRAME.prev_system_phase) {
+ restart = true;
+ if (params.use_fractional_delta) {
+ local_delta = (1.0 - restart_phase + FRAME.system_phase) * params.lifetime;
+ }
+
+ } else if (restart_phase < FRAME.system_phase) {
+ restart = true;
+ if (params.use_fractional_delta) {
+ local_delta = (FRAME.system_phase - restart_phase) * params.lifetime;
+ }
+ }
+ }
+
+ uint current_cycle = FRAME.cycle;
+
+ if (FRAME.system_phase < restart_phase) {
+ current_cycle -= uint(1);
+ }
+
+ uint particle_number = current_cycle * uint(params.total_particles) + particle;
+
+ if (restart) {
+ PARTICLE.is_active = FRAME.emitting;
+ restart_position = true;
+ restart_rotation_scale = true;
+ restart_velocity = true;
+ restart_color = true;
+ restart_custom = true;
+ }
+ }
+
+ if (PARTICLE.is_active) {
+ /* clang-format off */
+
+COMPUTE_SHADER_CODE
+
+ /* clang-format on */
+ }
+
+#if !defined(DISABLE_VELOCITY)
+
+ if (PARTICLE.is_active) {
+ PARTICLE.xform[3].xyz += PARTICLE.velocity * local_delta;
+ }
+#endif
+
+#if 0
+ if (PARTICLE.is_active) {
+ //execute shader
+
+
+
+
+ //!defined(DISABLE_FORCE)
+
+ if (false) {
+ vec3 force = vec3(0.0);
+ for (int i = 0; i < attractor_count; i++) {
+ vec3 rel_vec = xform[3].xyz - attractors[i].pos;
+ float dist = length(rel_vec);
+ if (attractors[i].radius < dist)
+ continue;
+ if (attractors[i].eat_radius > 0.0 && attractors[i].eat_radius > dist) {
+ out_velocity_active.a = 0.0;
+ }
+
+ rel_vec = normalize(rel_vec);
+
+ float attenuation = pow(dist / attractors[i].radius, attractors[i].attenuation);
+
+ if (attractors[i].dir == vec3(0.0)) {
+ //towards center
+ force += attractors[i].strength * rel_vec * attenuation * mass;
+ } else {
+ force += attractors[i].strength * attractors[i].dir * attenuation * mass;
+ }
+ }
+
+ out_velocity_active.xyz += force * local_delta;
+ }
+
+#if !defined(DISABLE_VELOCITY)
+
+ if (true) {
+ xform[3].xyz += out_velocity_active.xyz * local_delta;
+ }
+#endif
+ } else {
+ xform = mat4(0.0);
+ }
+
+
+ xform = transpose(xform);
+
+ out_velocity_active.a = mix(0.0, 1.0, shader_active);
+
+ out_xform_1 = xform[0];
+ out_xform_2 = xform[1];
+ out_xform_3 = xform[2];
+#endif
+}
diff --git a/servers/rendering/rasterizer_rd/shaders/particles_copy.glsl b/servers/rendering/rasterizer_rd/shaders/particles_copy.glsl
new file mode 100644
index 0000000000..6c782b6045
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/particles_copy.glsl
@@ -0,0 +1,82 @@
+#[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
+
+struct ParticleData {
+ mat4 xform;
+ vec3 velocity;
+ bool is_active;
+ vec4 color;
+ vec4 custom;
+};
+
+layout(set = 0, binding = 1, std430) restrict readonly buffer Particles {
+ ParticleData data[];
+}
+particles;
+
+layout(set = 0, binding = 2, std430) restrict writeonly buffer Transforms {
+ vec4 data[];
+}
+instances;
+
+#ifdef USE_SORT_BUFFER
+
+layout(set = 1, binding = 0, std430) restrict buffer SortBuffer {
+ vec2 data[];
+}
+sort_buffer;
+
+#endif // USE_SORT_BUFFER
+
+layout(push_constant, binding = 0, std430) uniform Params {
+ vec3 sort_direction;
+ uint total_particles;
+}
+params;
+
+void main() {
+#ifdef MODE_FILL_SORT_BUFFER
+
+ uint particle = gl_GlobalInvocationID.x;
+ if (particle >= params.total_particles) {
+ return; //discard
+ }
+
+ sort_buffer.data[particle].x = dot(params.sort_direction, particles.data[particle].xform[3].xyz);
+ sort_buffer.data[particle].y = float(particle);
+#endif
+
+#ifdef MODE_FILL_INSTANCES
+
+ uint particle = gl_GlobalInvocationID.x;
+ uint write_offset = gl_GlobalInvocationID.x * (3 + 1 + 1); //xform + color + custom
+
+ if (particle >= params.total_particles) {
+ return; //discard
+ }
+
+#ifdef USE_SORT_BUFFER
+ particle = uint(sort_buffer.data[particle].y); //use index from sort buffer
+#endif
+
+ mat4 txform;
+
+ if (particles.data[particle].is_active) {
+ txform = transpose(particles.data[particle].xform);
+ } else {
+ txform = mat4(vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)); //zero scale, becomes invisible
+ }
+
+ instances.data[write_offset + 0] = txform[0];
+ instances.data[write_offset + 1] = txform[1];
+ instances.data[write_offset + 2] = txform[2];
+ instances.data[write_offset + 3] = particles.data[particle].color;
+ instances.data[write_offset + 4] = particles.data[particle].custom;
+
+#endif
+}
diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
index 5993e68317..2a7b73d9aa 100644
--- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl
@@ -681,9 +681,13 @@ LIGHT_SHADER_CODE
#ifndef USE_NO_SHADOWS
-// Produces cheap but low-quality white noise, nothing special
+// Produces cheap white noise, optmized for window-space
+// Comes from: https://www.shadertoy.com/view/4djSRW
+// Copyright: Dave Hoskins, MIT License
float quick_hash(vec2 pos) {
- return fract(sin(dot(pos * 19.19, vec2(49.5791, 97.413))) * 49831.189237);
+ vec3 p3 = fract(vec3(pos.xyx) * .1031);
+ p3 += dot(p3, p3.yzx + 33.33);
+ return fract((p3.x + p3.y) * p3.z);
}
float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
diff --git a/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl b/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl
index d7d19897e3..dd0ca5c506 100644
--- a/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl
+++ b/servers/rendering/rasterizer_rd/shaders/sdfgi_preprocess.glsl
@@ -338,7 +338,7 @@ void main() {
continue; //was not initialized yet, ignore
}
- float q_dist = distance(posf, vec3(p.xyz));
+ float q_dist = distance(posf, vec3(q.xyz));
if (p.w == 0 || q_dist < p_dist) {
p = q; //just replace because current is unused
p_dist = q_dist;
diff --git a/servers/rendering/rasterizer_rd/shaders/sort.glsl b/servers/rendering/rasterizer_rd/shaders/sort.glsl
new file mode 100644
index 0000000000..e5ebb9c64b
--- /dev/null
+++ b/servers/rendering/rasterizer_rd/shaders/sort.glsl
@@ -0,0 +1,203 @@
+#[compute]
+
+#version 450
+
+VERSION_DEFINES
+
+// Original version here:
+// https://github.com/GPUOpen-LibrariesAndSDKs/GPUParticles11/blob/master/gpuparticles11/src/Shaders
+
+//
+// Copyright (c) 2016 Advanced Micro Devices, Inc. All rights reserved.
+//
+// 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.
+//
+
+#define SORT_SIZE 512
+#define NUM_THREADS (SORT_SIZE / 2)
+#define INVERSION (16 * 2 + 8 * 3)
+#define ITERATIONS 1
+
+layout(local_size_x = NUM_THREADS, local_size_y = 1, local_size_z = 1) in;
+
+#ifndef MODE_SORT_STEP
+
+shared vec2 g_LDS[SORT_SIZE];
+
+#endif
+
+layout(set = 1, binding = 0, std430) restrict buffer SortBuffer {
+ vec2 data[];
+}
+sort_buffer;
+
+layout(push_constant, binding = 0, std430) uniform Params {
+ uint total_elements;
+ uint pad[3];
+ ivec4 job_params;
+}
+params;
+
+void main() {
+#ifdef MODE_SORT_BLOCK
+
+ uvec3 Gid = gl_WorkGroupID;
+ uvec3 DTid = gl_GlobalInvocationID;
+ uvec3 GTid = gl_LocalInvocationID;
+ uint GI = gl_LocalInvocationIndex;
+
+ int GlobalBaseIndex = int((Gid.x * SORT_SIZE) + GTid.x);
+ int LocalBaseIndex = int(GI);
+ int numElementsInThreadGroup = int(min(SORT_SIZE, params.total_elements - (Gid.x * SORT_SIZE)));
+
+ // Load shared data
+
+ int i;
+ for (i = 0; i < 2 * ITERATIONS; ++i) {
+ if (GI + i * NUM_THREADS < numElementsInThreadGroup)
+ g_LDS[LocalBaseIndex + i * NUM_THREADS] = sort_buffer.data[GlobalBaseIndex + i * NUM_THREADS];
+ }
+
+ groupMemoryBarrier();
+ barrier();
+
+ // Bitonic sort
+ for (int nMergeSize = 2; nMergeSize <= SORT_SIZE; nMergeSize = nMergeSize * 2) {
+ for (int nMergeSubSize = nMergeSize >> 1; nMergeSubSize > 0; nMergeSubSize = nMergeSubSize >> 1) {
+ for (i = 0; i < ITERATIONS; ++i) {
+ int tmp_index = int(GI + NUM_THREADS * i);
+ int index_low = tmp_index & (nMergeSubSize - 1);
+ int index_high = 2 * (tmp_index - index_low);
+ int index = index_high + index_low;
+
+ int nSwapElem = nMergeSubSize == nMergeSize >> 1 ? index_high + (2 * nMergeSubSize - 1) - index_low : index_high + nMergeSubSize + index_low;
+ if (nSwapElem < numElementsInThreadGroup) {
+ vec2 a = g_LDS[index];
+ vec2 b = g_LDS[nSwapElem];
+
+ if (a.x > b.x) {
+ g_LDS[index] = b;
+ g_LDS[nSwapElem] = a;
+ }
+ }
+ groupMemoryBarrier();
+ barrier();
+ }
+ }
+ }
+
+ // Store shared data
+ for (i = 0; i < 2 * ITERATIONS; ++i) {
+ if (GI + i * NUM_THREADS < numElementsInThreadGroup) {
+ sort_buffer.data[GlobalBaseIndex + i * NUM_THREADS] = g_LDS[LocalBaseIndex + i * NUM_THREADS];
+ }
+ }
+
+#endif
+
+#ifdef MODE_SORT_STEP
+
+ uvec3 Gid = gl_WorkGroupID;
+ uvec3 GTid = gl_LocalInvocationID;
+
+ ivec4 tgp;
+
+ tgp.x = int(Gid.x) * 256;
+ tgp.y = 0;
+ tgp.z = int(params.total_elements);
+ tgp.w = min(512, max(0, tgp.z - int(Gid.x) * 512));
+
+ uint localID = int(tgp.x) + GTid.x; // calculate threadID within this sortable-array
+
+ uint index_low = localID & (params.job_params.x - 1);
+ uint index_high = 2 * (localID - index_low);
+
+ uint index = tgp.y + index_high + index_low;
+ uint nSwapElem = tgp.y + index_high + params.job_params.y + params.job_params.z * index_low;
+
+ if (nSwapElem < tgp.y + tgp.z) {
+ vec2 a = sort_buffer.data[index];
+ vec2 b = sort_buffer.data[nSwapElem];
+
+ if (a.x > b.x) {
+ sort_buffer.data[index] = b;
+ sort_buffer.data[nSwapElem] = a;
+ }
+ }
+
+#endif
+
+#ifdef MODE_SORT_INNER
+
+ uvec3 Gid = gl_WorkGroupID;
+ uvec3 DTid = gl_GlobalInvocationID;
+ uvec3 GTid = gl_LocalInvocationID;
+ uint GI = gl_LocalInvocationIndex;
+
+ ivec4 tgp;
+
+ tgp.x = int(Gid.x * 256);
+ tgp.y = 0;
+ tgp.z = int(params.total_elements.x);
+ tgp.w = int(min(512, max(0, params.total_elements - Gid.x * 512)));
+
+ int GlobalBaseIndex = int(tgp.y + tgp.x * 2 + GTid.x);
+ int LocalBaseIndex = int(GI);
+ int i;
+
+ // Load shared data
+ for (i = 0; i < 2; ++i) {
+ if (GI + i * NUM_THREADS < tgp.w)
+ g_LDS[LocalBaseIndex + i * NUM_THREADS] = sort_buffer.data[GlobalBaseIndex + i * NUM_THREADS];
+ }
+
+ groupMemoryBarrier();
+ barrier();
+
+ // sort threadgroup shared memory
+ for (int nMergeSubSize = SORT_SIZE >> 1; nMergeSubSize > 0; nMergeSubSize = nMergeSubSize >> 1) {
+ int tmp_index = int(GI);
+ int index_low = tmp_index & (nMergeSubSize - 1);
+ int index_high = 2 * (tmp_index - index_low);
+ int index = index_high + index_low;
+
+ int nSwapElem = index_high + nMergeSubSize + index_low;
+
+ if (nSwapElem < tgp.w) {
+ vec2 a = g_LDS[index];
+ vec2 b = g_LDS[nSwapElem];
+
+ if (a.x > b.x) {
+ g_LDS[index] = b;
+ g_LDS[nSwapElem] = a;
+ }
+ }
+ groupMemoryBarrier();
+ barrier();
+ }
+
+ // Store shared data
+ for (i = 0; i < 2; ++i) {
+ if (GI + i * NUM_THREADS < tgp.w) {
+ sort_buffer.data[GlobalBaseIndex + i * NUM_THREADS] = g_LDS[LocalBaseIndex + i * NUM_THREADS];
+ }
+ }
+
+#endif
+}
diff --git a/servers/rendering/rendering_server_canvas.cpp b/servers/rendering/rendering_server_canvas.cpp
index 5c0741bb3b..07eabfd430 100644
--- a/servers/rendering/rendering_server_canvas.cpp
+++ b/servers/rendering/rendering_server_canvas.cpp
@@ -900,13 +900,12 @@ void RenderingServerCanvas::canvas_item_attach_skeleton(RID p_item, RID p_skelet
void RenderingServerCanvas::canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect) {
Item *canvas_item = canvas_item_owner.getornull(p_item);
ERR_FAIL_COND(!canvas_item);
- if (bool(canvas_item->copy_back_buffer != nullptr) != p_enable) {
- if (p_enable) {
- canvas_item->copy_back_buffer = memnew(RasterizerCanvas::Item::CopyBackBuffer);
- } else {
- memdelete(canvas_item->copy_back_buffer);
- canvas_item->copy_back_buffer = nullptr;
- }
+ if (p_enable && (canvas_item->copy_back_buffer == nullptr)) {
+ canvas_item->copy_back_buffer = memnew(RasterizerCanvas::Item::CopyBackBuffer);
+ }
+ if (!p_enable && (canvas_item->copy_back_buffer != nullptr)) {
+ memdelete(canvas_item->copy_back_buffer);
+ canvas_item->copy_back_buffer = nullptr;
}
if (p_enable) {
diff --git a/servers/rendering/rendering_server_raster.h b/servers/rendering/rendering_server_raster.h
index b4eac8cd76..ceefcfa1fc 100644
--- a/servers/rendering/rendering_server_raster.h
+++ b/servers/rendering/rendering_server_raster.h
@@ -442,6 +442,8 @@ public:
BIND1R(bool, particles_is_inactive, RID)
BIND1(particles_request_process, RID)
BIND1(particles_restart, RID)
+ BIND6(particles_emit, RID, const Transform &, const Vector3 &, const Color &, const Color &, uint32_t)
+ BIND2(particles_set_subemitter, RID, RID)
BIND2(particles_set_draw_order, RID, RS::ParticlesDrawOrder)
@@ -557,6 +559,7 @@ public:
BIND11(environment_set_glow, RID, bool, int, float, float, float, float, EnvironmentGlowBlendMode, float, float, float)
BIND1(environment_glow_set_use_bicubic_upscale, bool)
+ BIND1(environment_glow_set_use_high_quality, bool)
BIND9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float)
diff --git a/servers/rendering/rendering_server_scene.cpp b/servers/rendering/rendering_server_scene.cpp
index 2024f5b983..d8e52a5aae 100644
--- a/servers/rendering/rendering_server_scene.cpp
+++ b/servers/rendering/rendering_server_scene.cpp
@@ -2044,6 +2044,7 @@ void RenderingServerScene::_prepare_scene(const Transform p_cam_transform, const
keep = false;
} else {
RSG::storage->particles_request_process(ins->base);
+ RSG::storage->particles_set_view_axis(ins->base, -p_cam_transform.basis.get_axis(2).normalized());
//particles visible? request redraw
RenderingServerRaster::redraw_request();
}
diff --git a/servers/rendering/rendering_server_wrap_mt.h b/servers/rendering/rendering_server_wrap_mt.h
index fb5c161c8a..a8a56e7d56 100644
--- a/servers/rendering/rendering_server_wrap_mt.h
+++ b/servers/rendering/rendering_server_wrap_mt.h
@@ -360,11 +360,14 @@ public:
FUNC1(particles_request_process, RID)
FUNC1(particles_restart, RID)
+ FUNC6(particles_emit, RID, const Transform &, const Vector3 &, const Color &, const Color &, uint32_t)
+
FUNC2(particles_set_draw_order, RID, RS::ParticlesDrawOrder)
FUNC2(particles_set_draw_passes, RID, int)
FUNC3(particles_set_draw_pass_mesh, RID, int, RID)
FUNC2(particles_set_emission_transform, RID, const Transform &)
+ FUNC2(particles_set_subemitter, RID, RID)
FUNC1R(AABB, particles_get_current_aabb, RID)
@@ -474,6 +477,7 @@ public:
FUNC11(environment_set_glow, RID, bool, int, float, float, float, float, EnvironmentGlowBlendMode, float, float, float)
FUNC1(environment_glow_set_use_bicubic_upscale, bool)
+ FUNC1(environment_glow_set_use_high_quality, bool)
FUNC9(environment_set_tonemap, RID, EnvironmentToneMapper, float, float, bool, float, float, float, float)
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index d6acad83f7..28c41fb2dc 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -33,15 +33,15 @@
#include "core/print_string.h"
#include "servers/rendering_server.h"
-static bool _is_text_char(CharType c) {
+static bool _is_text_char(char32_t c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
-static bool _is_number(CharType c) {
+static bool _is_number(char32_t c) {
return (c >= '0' && c <= '9');
}
-static bool _is_hex(CharType c) {
+static bool _is_hex(char32_t c) {
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
@@ -334,7 +334,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
};
ShaderLanguage::Token ShaderLanguage::_get_token() {
-#define GETCHAR(m_idx) (((char_idx + m_idx) < code.length()) ? code[char_idx + m_idx] : CharType(0))
+#define GETCHAR(m_idx) (((char_idx + m_idx) < code.length()) ? code[char_idx + m_idx] : char32_t(0))
while (true) {
char_idx++;
@@ -582,11 +582,11 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
break;
}
- str += CharType(GETCHAR(i));
+ str += char32_t(GETCHAR(i));
i++;
}
- CharType last_char = str[str.length() - 1];
+ char32_t last_char = str[str.length() - 1];
if (hexa_found) {
//integer(hex)
@@ -663,7 +663,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() {
String str;
while (_is_text_char(GETCHAR(0))) {
- str += CharType(GETCHAR(0));
+ str += char32_t(GETCHAR(0));
char_idx++;
}
@@ -920,13 +920,13 @@ void ShaderLanguage::clear() {
}
}
-bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_reassign, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name) {
- if (p_builtin_types.has(p_identifier)) {
+bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name) {
+ if (p_function_info.built_ins.has(p_identifier)) {
if (r_data_type) {
- *r_data_type = p_builtin_types[p_identifier].type;
+ *r_data_type = p_function_info.built_ins[p_identifier].type;
}
if (r_is_const) {
- *r_is_const = p_builtin_types[p_identifier].constant;
+ *r_is_const = p_function_info.built_ins[p_identifier].constant;
}
if (r_type) {
*r_type = IDENTIFIER_BUILTIN_VAR;
@@ -935,6 +935,20 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
return true;
}
+ if (p_function_info.stage_functions.has(p_identifier)) {
+ if (r_data_type) {
+ *r_data_type = p_function_info.stage_functions[p_identifier].return_type;
+ }
+ if (r_is_const) {
+ *r_is_const = true;
+ }
+ if (r_type) {
+ *r_type = IDENTIFIER_FUNCTION;
+ }
+
+ return true;
+ }
+
FunctionNode *function = nullptr;
while (p_block) {
@@ -2152,7 +2166,7 @@ const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[]
{ nullptr, 0 }
};
-bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str) {
+bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str) {
ERR_FAIL_COND_V(p_func->op != OP_CALL && p_func->op != OP_CONSTRUCT, false);
Vector<DataType> args;
@@ -2169,6 +2183,30 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin
int argcount = args.size();
+ if (p_function_info.stage_functions.has(name)) {
+ //stage based function
+ const StageFunctionInfo &sf = p_function_info.stage_functions[name];
+ if (argcount != sf.arguments.size()) {
+ _set_error(vformat("Invalid number of arguments when calling stage function '%s', which expects %d arguments.", String(name), sf.arguments.size()));
+ return false;
+ }
+ //validate arguments
+ for (int i = 0; i < argcount; i++) {
+ if (args[i] != sf.arguments[i].type) {
+ _set_error(vformat("Invalid argument type when calling stage function '%s', type expected is '%s'.", String(name), String(get_datatype_name(sf.arguments[i].type))));
+ return false;
+ }
+ }
+
+ if (r_ret_type) {
+ *r_ret_type = sf.return_type;
+ }
+ if (r_ret_type_str) {
+ *r_ret_type_str = "";
+ }
+ return true;
+ }
+
bool failed_builtin = false;
bool unsupported_builtin = false;
int builtin_idx = 0;
@@ -2241,8 +2279,8 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin
if (shader->uniforms.has(varname)) {
fail = true;
} else {
- if (p_builtin_types.has(varname)) {
- BuiltInInfo info = p_builtin_types[varname];
+ if (p_function_info.built_ins.has(varname)) {
+ BuiltInInfo info = p_function_info.built_ins[varname];
if (info.constant) {
fail = true;
}
@@ -2278,7 +2316,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin
const BlockNode *b = p_block;
bool valid = false;
while (b) {
- if (b->variables.has(var_name) || p_builtin_types.has(var_name)) {
+ if (b->variables.has(var_name) || p_function_info.built_ins.has(var_name)) {
valid = true;
break;
}
@@ -2353,10 +2391,13 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin
err += ",";
}
- if (p_func->arguments[i + 1]->type == Node::TYPE_CONSTANT && p_func->arguments[i + 1]->get_datatype() == TYPE_INT && static_cast<ConstantNode *>(p_func->arguments[i + 1])->values[0].sint < 0) {
- err += "-";
+ String arg_name;
+ if (args[i] == TYPE_STRUCT) {
+ arg_name = args2[i];
+ } else {
+ arg_name = get_datatype_name(args[i]);
}
- err += get_datatype_name(args[i]);
+ err += arg_name;
}
err += ")";
_set_error(err);
@@ -2380,6 +2421,9 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin
return false;
}
+ int last_arg_count = 0;
+ String arg_list = "";
+
for (int i = 0; i < shader->functions.size(); i++) {
if (name != shader->functions[i].name) {
continue;
@@ -2391,21 +2435,45 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin
}
FunctionNode *pfunc = shader->functions[i].function;
+ if (arg_list == "") {
+ for (int j = 0; j < pfunc->arguments.size(); j++) {
+ if (j > 0) {
+ arg_list += ", ";
+ }
+ String func_arg_name;
+ if (pfunc->arguments[j].type == TYPE_STRUCT) {
+ func_arg_name = pfunc->arguments[j].type_str;
+ } else {
+ func_arg_name = get_datatype_name(pfunc->arguments[j].type);
+ }
+ arg_list += func_arg_name;
+ }
+ }
if (pfunc->arguments.size() != args.size()) {
+ last_arg_count = pfunc->arguments.size();
continue;
}
bool fail = false;
for (int j = 0; j < args.size(); j++) {
- if (args[j] == TYPE_STRUCT && args2[j] != pfunc->arguments[j].type_str) {
- fail = true;
- break;
- }
if (get_scalar_type(args[j]) == args[j] && p_func->arguments[j + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[j + 1]), pfunc->arguments[j].type)) {
//all good, but it needs implicit conversion later
- } else if (args[j] != pfunc->arguments[j].type) {
+ } else if (args[j] != pfunc->arguments[j].type || (args[j] == TYPE_STRUCT && args2[j] != pfunc->arguments[j].type_str)) {
+ String func_arg_name;
+ if (pfunc->arguments[j].type == TYPE_STRUCT) {
+ func_arg_name = pfunc->arguments[j].type_str;
+ } else {
+ func_arg_name = get_datatype_name(pfunc->arguments[j].type);
+ }
+ String arg_name;
+ if (args[j] == TYPE_STRUCT) {
+ arg_name = args2[j];
+ } else {
+ arg_name = get_datatype_name(args[j]);
+ }
+ _set_error(vformat("Invalid argument for \"%s(%s)\" function: argument %s should be %s but is %s.", String(name), arg_list, j + 1, func_arg_name, arg_name));
fail = true;
break;
}
@@ -2441,6 +2509,12 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const Map<Strin
}
}
+ if (last_arg_count > args.size()) {
+ _set_error(vformat("Too few arguments for \"%s(%s)\" call. Expected at least %s but received %s.", String(name), arg_list, last_arg_count, args.size()));
+ } else if (last_arg_count < args.size()) {
+ _set_error(vformat("Too many arguments for \"%s(%s)\" call. Expected at most %s but received %s.", String(name), arg_list, last_arg_count, args.size()));
+ }
+
return false;
}
@@ -2456,7 +2530,7 @@ bool ShaderLanguage::_compare_datatypes_in_nodes(Node *a, Node *b) const {
return true;
}
-bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg) {
+bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, int *r_complete_arg) {
TkPos pos = _get_tkpos();
Token tk = _get_token();
@@ -2478,7 +2552,7 @@ bool ShaderLanguage::_parse_function_arguments(BlockNode *p_block, const Map<Str
}
}
- Node *arg = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *arg = _parse_and_reduce_expression(p_block, p_function_info);
if (!arg) {
return false;
@@ -3017,16 +3091,16 @@ bool ShaderLanguage::_is_operator_assign(Operator p_op) const {
return false;
}
-bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types, String *r_message) {
+bool ShaderLanguage::_validate_assign(Node *p_node, const FunctionInfo &p_function_info, String *r_message) {
if (p_node->type == Node::TYPE_OPERATOR) {
OperatorNode *op = static_cast<OperatorNode *>(p_node);
if (op->op == OP_INDEX) {
- return _validate_assign(op->arguments[0], p_builtin_types, r_message);
+ return _validate_assign(op->arguments[0], p_function_info, r_message);
} else if (_is_operator_assign(op->op)) {
//chained assignment
- return _validate_assign(op->arguments[1], p_builtin_types, r_message);
+ return _validate_assign(op->arguments[1], p_function_info, r_message);
} else if (op->op == OP_CALL) {
if (r_message) {
@@ -3045,7 +3119,7 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI
return false;
}
- return _validate_assign(member->owner, p_builtin_types, r_message);
+ return _validate_assign(member->owner, p_function_info, r_message);
} else if (p_node->type == Node::TYPE_VARIABLE) {
VariableNode *var = static_cast<VariableNode *>(p_node);
@@ -3071,7 +3145,7 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI
return false;
}
- if (!(p_builtin_types.has(var->name) && p_builtin_types[var->name].constant)) {
+ if (!(p_function_info.built_ins.has(var->name) && p_function_info.built_ins[var->name].constant)) {
return true;
}
} else if (p_node->type == Node::TYPE_ARRAY) {
@@ -3168,7 +3242,7 @@ bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringNa
ERR_FAIL_V(false); //bug? function not found
}
-ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types) {
+ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info) {
Vector<Expression> expression;
//Vector<TokenType> operators;
@@ -3184,7 +3258,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (tk.type == TK_PARENTHESIS_OPEN) {
//handle subexpression
- expr = _parse_and_reduce_expression(p_block, p_builtin_types);
+ expr = _parse_and_reduce_expression(p_block, p_function_info);
if (!expr) {
return nullptr;
}
@@ -3257,7 +3331,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
int carg = -1;
- bool ok = _parse_function_arguments(p_block, p_builtin_types, func, &carg);
+ bool ok = _parse_function_arguments(p_block, p_function_info, func, &carg);
if (carg >= 0) {
completion_type = COMPLETION_CALL_ARGUMENTS;
@@ -3271,7 +3345,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr;
}
- if (!_validate_function_call(p_block, p_builtin_types, func, &func->return_cache, &func->struct_name)) {
+ if (!_validate_function_call(p_block, p_function_info, func, &func->return_cache, &func->struct_name)) {
_set_error("No matching constructor found for: '" + String(funcname->name) + "'");
return nullptr;
}
@@ -3347,7 +3421,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else {
_set_tkpos(pos2);
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
_set_error("Expected single integer constant > 0");
return nullptr;
@@ -3408,7 +3482,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (tk.type == TK_PARENTHESIS_OPEN || auto_size) { // initialization
while (true) {
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n) {
return nullptr;
}
@@ -3448,7 +3522,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
nexpr = an;
} else {
- nexpr = _parse_and_reduce_expression(p_block, p_builtin_types);
+ nexpr = _parse_and_reduce_expression(p_block, p_function_info);
if (!nexpr) {
return nullptr;
}
@@ -3490,7 +3564,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
int carg = -1;
- bool ok = _parse_function_arguments(p_block, p_builtin_types, func, &carg);
+ bool ok = _parse_function_arguments(p_block, p_function_info, func, &carg);
// Check if block has a variable with the same name as function to prevent shader crash.
ShaderLanguage::BlockNode *bnode = p_block;
@@ -3532,7 +3606,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr;
}
- if (!_validate_function_call(p_block, p_builtin_types, func, &func->return_cache, &func->struct_name)) {
+ if (!_validate_function_call(p_block, p_function_info, func, &func->return_cache, &func->struct_name)) {
_set_error("No matching function found for: '" + String(funcname->name) + "'");
return nullptr;
}
@@ -3584,8 +3658,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else if (shader->uniforms.has(varname)) {
error = true;
} else {
- if (p_builtin_types.has(varname)) {
- BuiltInInfo info = p_builtin_types[varname];
+ if (p_function_info.built_ins.has(varname)) {
+ BuiltInInfo info = p_function_info.built_ins[varname];
if (info.constant) {
error = true;
}
@@ -3617,7 +3691,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (!_propagate_function_call_sampler_uniform_settings(name, i, u->filter, u->repeat)) {
return nullptr;
}
- } else if (p_builtin_types.has(varname)) {
+ } else if (p_function_info.built_ins.has(varname)) {
//a built-in
if (!_propagate_function_call_sampler_builtin_reference(name, i, varname)) {
return nullptr;
@@ -3672,7 +3746,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr;
}
} else {
- if (!_find_identifier(p_block, false, p_builtin_types, identifier, &data_type, &ident_type, &is_const, &array_size, &struct_name)) {
+ if (!_find_identifier(p_block, false, p_function_info, identifier, &data_type, &ident_type, &is_const, &array_size, &struct_name)) {
_set_error("Unknown identifier in expression: " + String(identifier));
return nullptr;
}
@@ -3697,7 +3771,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (tk.type == TK_PERIOD) {
completion_class = TAG_ARRAY;
p_block->block_tag = SubClassTag::TAG_ARRAY;
- call_expression = _parse_and_reduce_expression(p_block, p_builtin_types);
+ call_expression = _parse_and_reduce_expression(p_block, p_function_info);
p_block->block_tag = SubClassTag::TAG_GLOBAL;
if (!call_expression) {
return nullptr;
@@ -3705,7 +3779,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
data_type = call_expression->get_datatype();
} else { // indexing
- index_expression = _parse_and_reduce_expression(p_block, p_builtin_types);
+ index_expression = _parse_and_reduce_expression(p_block, p_function_info);
if (!index_expression) {
return nullptr;
}
@@ -3869,7 +3943,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
break;
}
- const CharType *c = ident.ptr();
+ const char32_t *c = ident.ptr();
for (int i = 0; i < l; i++) {
switch (c[i]) {
case 'r':
@@ -3933,7 +4007,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
break;
}
- const CharType *c = ident.ptr();
+ const char32_t *c = ident.ptr();
for (int i = 0; i < l; i++) {
switch (c[i]) {
case 'r':
@@ -4000,7 +4074,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
break;
}
- const CharType *c = ident.ptr();
+ const char32_t *c = ident.ptr();
for (int i = 0; i < l; i++) {
switch (c[i]) {
case 'r':
@@ -4085,7 +4159,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
_set_error("Nested array length() is not yet implemented");
return nullptr;
} else if (tk.type == TK_BRACKET_OPEN) {
- Node *index_expression = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *index_expression = _parse_and_reduce_expression(p_block, p_function_info);
if (!index_expression) {
return nullptr;
}
@@ -4134,7 +4208,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
*/
} else if (tk.type == TK_BRACKET_OPEN) {
- Node *index = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *index = _parse_and_reduce_expression(p_block, p_function_info);
if (!index) {
return nullptr;
}
@@ -4276,7 +4350,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr;
}
- if (!_validate_assign(expr, p_builtin_types)) {
+ if (!_validate_assign(expr, p_function_info)) {
_set_error("Invalid use of increment/decrement operator in constant expression.");
return nullptr;
}
@@ -4574,7 +4648,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
for (int i = expr_pos - 1; i >= next_op; i--) {
OperatorNode *op = alloc_node<OperatorNode>();
op->op = expression[i].op;
- if ((op->op == OP_INCREMENT || op->op == OP_DECREMENT) && !_validate_assign(expression[i + 1].node, p_builtin_types)) {
+ if ((op->op == OP_INCREMENT || op->op == OP_DECREMENT) && !_validate_assign(expression[i + 1].node, p_function_info)) {
_set_error("Can't use increment/decrement operator in constant expression.");
return nullptr;
}
@@ -4648,7 +4722,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (_is_operator_assign(op->op)) {
String assign_message;
- if (!_validate_assign(expression[next_op - 1].node, p_builtin_types, &assign_message)) {
+ if (!_validate_assign(expression[next_op - 1].node, p_function_info, &assign_message)) {
_set_error(assign_message);
return nullptr;
}
@@ -4802,8 +4876,8 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
return p_node;
}
-ShaderLanguage::Node *ShaderLanguage::_parse_and_reduce_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types) {
- ShaderLanguage::Node *expr = _parse_expression(p_block, p_builtin_types);
+ShaderLanguage::Node *ShaderLanguage::_parse_and_reduce_expression(BlockNode *p_block, const FunctionInfo &p_function_info) {
+ ShaderLanguage::Node *expr = _parse_expression(p_block, p_function_info);
if (!expr) { //errored
return nullptr;
}
@@ -4813,7 +4887,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_and_reduce_expression(BlockNode *p_
return expr;
}
-Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, bool p_just_one, bool p_can_break, bool p_can_continue) {
+Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_function_info, bool p_just_one, bool p_can_break, bool p_can_continue) {
while (true) {
TkPos pos = _get_tkpos();
@@ -4897,7 +4971,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
StringName name = tk.text;
ShaderLanguage::IdentifierType itype;
- if (_find_identifier(p_block, true, p_builtin_types, name, (ShaderLanguage::DataType *)nullptr, &itype)) {
+ if (_find_identifier(p_block, true, p_function_info, name, (ShaderLanguage::DataType *)nullptr, &itype)) {
if (itype != IDENTIFIER_FUNCTION) {
_set_error("Redefinition of '" + String(name) + "'");
return ERR_PARSE_ERROR;
@@ -5016,7 +5090,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
} else {
_set_tkpos(pos2);
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
_set_error("Expected single integer constant > 0");
return ERR_PARSE_ERROR;
@@ -5097,7 +5171,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
if (tk.type == TK_PARENTHESIS_OPEN || curly) { // initialization
while (true) {
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n) {
return ERR_PARSE_ERROR;
}
@@ -5169,7 +5243,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
decl.initializer = nullptr;
//variable created with assignment! must parse an expression
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n) {
return ERR_PARSE_ERROR;
}
@@ -5229,7 +5303,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
//a sub block, just because..
BlockNode *block = alloc_node<BlockNode>();
block->parent_block = p_block;
- if (_parse_block(block, p_builtin_types, false, p_can_break, p_can_continue) != OK) {
+ if (_parse_block(block, p_function_info, false, p_can_break, p_can_continue) != OK) {
return ERR_PARSE_ERROR;
}
p_block->statements.push_back(block);
@@ -5243,7 +5317,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
ControlFlowNode *cf = alloc_node<ControlFlowNode>();
cf->flow_op = FLOW_OP_IF;
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n) {
return ERR_PARSE_ERROR;
}
@@ -5265,7 +5339,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
cf->blocks.push_back(block);
p_block->statements.push_back(cf);
- Error err = _parse_block(block, p_builtin_types, true, p_can_break, p_can_continue);
+ Error err = _parse_block(block, p_function_info, true, p_can_break, p_can_continue);
if (err) {
return err;
}
@@ -5276,7 +5350,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
block = alloc_node<BlockNode>();
block->parent_block = p_block;
cf->blocks.push_back(block);
- err = _parse_block(block, p_builtin_types, true, p_can_break, p_can_continue);
+ err = _parse_block(block, p_function_info, true, p_can_break, p_can_continue);
} else {
_set_tkpos(pos); //rollback
@@ -5295,7 +5369,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
}
ControlFlowNode *cf = alloc_node<ControlFlowNode>();
cf->flow_op = FLOW_OP_SWITCH;
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n) {
return ERR_PARSE_ERROR;
}
@@ -5323,7 +5397,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
int prev_type = TK_CF_CASE;
while (true) { // Go-through multiple cases.
- if (_parse_block(switch_block, p_builtin_types, true, true, false) != OK) {
+ if (_parse_block(switch_block, p_function_info, true, true, false) != OK) {
return ERR_PARSE_ERROR;
}
pos = _get_tkpos();
@@ -5424,7 +5498,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
cf->blocks.push_back(case_block);
p_block->statements.push_back(cf);
- Error err = _parse_block(case_block, p_builtin_types, false, true, false);
+ Error err = _parse_block(case_block, p_function_info, false, true, false);
if (err) {
return err;
}
@@ -5458,7 +5532,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
cf->blocks.push_back(default_block);
p_block->statements.push_back(cf);
- Error err = _parse_block(default_block, p_builtin_types, false, true, false);
+ Error err = _parse_block(default_block, p_function_info, false, true, false);
if (err) {
return err;
}
@@ -5475,7 +5549,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
do_block = alloc_node<BlockNode>();
do_block->parent_block = p_block;
- Error err = _parse_block(do_block, p_builtin_types, true, true, true);
+ Error err = _parse_block(do_block, p_function_info, true, true, true);
if (err) {
return err;
}
@@ -5499,7 +5573,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
} else {
cf->flow_op = FLOW_OP_WHILE;
}
- Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n) {
return ERR_PARSE_ERROR;
}
@@ -5516,7 +5590,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
cf->blocks.push_back(block);
p_block->statements.push_back(cf);
- Error err = _parse_block(block, p_builtin_types, true, true, true);
+ Error err = _parse_block(block, p_function_info, true, true, true);
if (err) {
return err;
}
@@ -5547,11 +5621,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
init_block->parent_block = p_block;
init_block->single_statement = true;
cf->blocks.push_back(init_block);
- if (_parse_block(init_block, p_builtin_types, true, false, false) != OK) {
+ if (_parse_block(init_block, p_function_info, true, false, false) != OK) {
return ERR_PARSE_ERROR;
}
- Node *n = _parse_and_reduce_expression(init_block, p_builtin_types);
+ Node *n = _parse_and_reduce_expression(init_block, p_function_info);
if (!n) {
return ERR_PARSE_ERROR;
}
@@ -5569,7 +5643,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
cf->expressions.push_back(n);
- n = _parse_and_reduce_expression(init_block, p_builtin_types);
+ n = _parse_and_reduce_expression(init_block, p_function_info);
if (!n) {
return ERR_PARSE_ERROR;
}
@@ -5587,7 +5661,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
cf->blocks.push_back(block);
p_block->statements.push_back(cf);
- Error err = _parse_block(block, p_builtin_types, true, true, true);
+ Error err = _parse_block(block, p_function_info, true, true, true);
if (err) {
return err;
}
@@ -5623,7 +5697,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
}
} else {
_set_tkpos(pos); //rollback, wants expression
- Node *expr = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *expr = _parse_and_reduce_expression(p_block, p_function_info);
if (!expr) {
return ERR_PARSE_ERROR;
}
@@ -5725,7 +5799,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
} else {
//nothing else, so expression
_set_tkpos(pos); //rollback
- Node *expr = _parse_and_reduce_expression(p_block, p_builtin_types);
+ Node *expr = _parse_and_reduce_expression(p_block, p_function_info);
if (!expr) {
return ERR_PARSE_ERROR;
}
@@ -6066,7 +6140,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
name = tk.text;
- if (_find_identifier(nullptr, false, Map<StringName, BuiltInInfo>(), name)) {
+ if (_find_identifier(nullptr, false, FunctionInfo(), name)) {
_set_error("Redefinition of '" + String(name) + "'");
return ERR_PARSE_ERROR;
}
@@ -6315,7 +6389,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
//reset scope for next uniform
if (tk.type == TK_OP_ASSIGN) {
- Node *expr = _parse_and_reduce_expression(nullptr, Map<StringName, BuiltInInfo>());
+ Node *expr = _parse_and_reduce_expression(nullptr, FunctionInfo());
if (!expr) {
return ERR_PARSE_ERROR;
}
@@ -6440,7 +6514,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
return ERR_PARSE_ERROR;
}
- if (_find_identifier(nullptr, false, Map<StringName, BuiltInInfo>(), name)) {
+ if (_find_identifier(nullptr, false, FunctionInfo(), name)) {
_set_error("Redefinition of '" + String(name) + "'");
return ERR_PARSE_ERROR;
}
@@ -6553,7 +6627,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
} else {
_set_tkpos(pos2);
- Node *n = _parse_and_reduce_expression(NULL, Map<StringName, BuiltInInfo>());
+ Node *n = _parse_and_reduce_expression(NULL, FunctionInfo());
if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
_set_error("Expected single integer constant > 0");
return ERR_PARSE_ERROR;
@@ -6634,7 +6708,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
if (tk.type == TK_PARENTHESIS_OPEN || curly) { // initialization
while (true) {
- Node *n = _parse_and_reduce_expression(NULL, Map<StringName, BuiltInInfo>());
+ Node *n = _parse_and_reduce_expression(NULL, FunctionInfo());
if (!n) {
return ERR_PARSE_ERROR;
}
@@ -6689,7 +6763,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
constant.initializer = static_cast<ConstantNode *>(expr);
} else {
//variable created with assignment! must parse an expression
- Node *expr = _parse_and_reduce_expression(NULL, Map<StringName, BuiltInInfo>());
+ Node *expr = _parse_and_reduce_expression(NULL, FunctionInfo());
if (!expr)
return ERR_PARSE_ERROR;
if (expr->type == Node::TYPE_OPERATOR && ((OperatorNode *)expr)->op == OP_CALL) {
@@ -6726,7 +6800,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
name = tk.text;
- if (_find_identifier(nullptr, false, Map<StringName, BuiltInInfo>(), name)) {
+ if (_find_identifier(nullptr, false, FunctionInfo(), name)) {
_set_error("Redefinition of '" + String(name) + "'");
return ERR_PARSE_ERROR;
}
@@ -6749,14 +6823,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
break;
}
- Map<StringName, BuiltInInfo> builtin_types;
+ FunctionInfo builtins;
if (p_functions.has(name)) {
- builtin_types = p_functions[name].built_ins;
+ builtins = p_functions[name];
}
if (p_functions.has("global")) { // Adds global variables: 'TIME'
for (Map<StringName, BuiltInInfo>::Element *E = p_functions["global"].built_ins.front(); E; E = E->next()) {
- builtin_types.insert(E->key(), E->value());
+ builtins.built_ins.insert(E->key(), E->value());
}
}
@@ -6879,7 +6953,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
pname = tk.text;
ShaderLanguage::IdentifierType itype;
- if (_find_identifier(func_node->body, false, builtin_types, pname, (ShaderLanguage::DataType *)nullptr, &itype)) {
+ if (_find_identifier(func_node->body, false, builtins, pname, (ShaderLanguage::DataType *)nullptr, &itype)) {
if (itype != IDENTIFIER_FUNCTION) {
_set_error("Redefinition of '" + String(pname) + "'");
return ERR_PARSE_ERROR;
@@ -6941,7 +7015,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
current_function = name;
- Error err = _parse_block(func_node->body, builtin_types);
+ Error err = _parse_block(func_node->body, builtins);
if (err) {
return err;
}
@@ -6979,6 +7053,11 @@ bool ShaderLanguage::has_builtin(const Map<StringName, ShaderLanguage::FunctionI
return true;
}
}
+ if (p_functions.has("compute")) {
+ if (p_functions["compute"].built_ins.has(p_name)) {
+ return true;
+ }
+ }
return false;
}
@@ -7034,7 +7113,7 @@ Error ShaderLanguage::_find_last_flow_op_in_block(BlockNode *p_block, FlowOperat
static int _get_first_ident_pos(const String &p_code) {
int idx = 0;
-#define GETCHAR(m_idx) (((idx + m_idx) < p_code.length()) ? p_code[idx + m_idx] : CharType(0))
+#define GETCHAR(m_idx) (((idx + m_idx) < p_code.length()) ? p_code[idx + m_idx] : char32_t(0))
while (true) {
if (GETCHAR(0) == '/' && GETCHAR(1) == '/') {
@@ -7295,7 +7374,7 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
}
if (j == completion_argument) {
- calltip += CharType(0xFFFF);
+ calltip += char32_t(0xFFFF);
}
if (shader->functions[i].function->arguments[j].is_const) {
@@ -7315,7 +7394,7 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
calltip += shader->functions[i].function->arguments[j].name;
if (j == completion_argument) {
- calltip += CharType(0xFFFF);
+ calltip += char32_t(0xFFFF);
}
}
@@ -7378,7 +7457,7 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
}
if (i == completion_argument) {
- calltip += CharType(0xFFFF);
+ calltip += char32_t(0xFFFF);
}
if (out_arg >= 0 && i == out_arg) {
@@ -7388,7 +7467,7 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
calltip += get_datatype_name(builtin_func_defs[idx].args[i]);
if (i == completion_argument) {
- calltip += CharType(0xFFFF);
+ calltip += char32_t(0xFFFF);
}
found_arg = true;
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index faf06a9a85..0d044a21c7 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -730,8 +730,25 @@ public:
constant(p_constant) {}
};
+ struct StageFunctionInfo {
+ struct Argument {
+ StringName name;
+ DataType type;
+
+ Argument(const StringName &p_name = StringName(), DataType p_type = TYPE_VOID) {
+ name = p_name;
+ type = p_type;
+ }
+ };
+
+ Vector<Argument> arguments;
+ DataType return_type = TYPE_VOID;
+ };
+
struct FunctionInfo {
Map<StringName, BuiltInInfo> built_ins;
+ Map<StringName, StageFunctionInfo> stage_functions;
+
bool can_discard;
};
static bool has_builtin(const Map<StringName, ShaderLanguage::FunctionInfo> &p_functions, const StringName &p_name);
@@ -802,9 +819,9 @@ private:
IDENTIFIER_CONSTANT,
};
- bool _find_identifier(const BlockNode *p_block, bool p_allow_reassign, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type = nullptr, IdentifierType *r_type = nullptr, bool *r_is_const = nullptr, int *r_array_size = nullptr, StringName *r_struct_name = nullptr);
+ bool _find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type = nullptr, IdentifierType *r_type = nullptr, bool *r_is_const = nullptr, int *r_array_size = nullptr, StringName *r_struct_name = nullptr);
bool _is_operator_assign(Operator p_op) const;
- bool _validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types, String *r_message = nullptr);
+ bool _validate_assign(Node *p_node, const FunctionInfo &p_function_info, String *r_message = nullptr);
bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = nullptr);
struct BuiltinFuncDef {
@@ -837,16 +854,16 @@ private:
Error _validate_datatype(DataType p_type);
bool _compare_datatypes_in_nodes(Node *a, Node *b) const;
- bool _validate_function_call(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str);
- bool _parse_function_arguments(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, OperatorNode *p_func, int *r_complete_arg = nullptr);
+ bool _validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str);
+ bool _parse_function_arguments(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, int *r_complete_arg = nullptr);
bool _propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat);
bool _propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin);
- Node *_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types);
+ Node *_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info);
ShaderLanguage::Node *_reduce_expression(BlockNode *p_block, ShaderLanguage::Node *p_node);
- Node *_parse_and_reduce_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types);
- Error _parse_block(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, bool p_just_one = false, bool p_can_break = false, bool p_can_continue = false);
+ Node *_parse_and_reduce_expression(BlockNode *p_block, const FunctionInfo &p_function_info);
+ Error _parse_block(BlockNode *p_block, const FunctionInfo &p_function_info, bool p_just_one = false, bool p_can_break = false, bool p_can_continue = false);
String _get_shader_type_list(const Set<String> &p_shader_types) const;
String _get_qualifier_str(ArgumentQualifier p_qualifier) const;
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index 76aeb5989c..f3ef322ad7 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -270,20 +270,41 @@ ShaderTypes::ShaderTypes() {
/************ PARTICLES **************************/
shader_modes[RS::SHADER_PARTICLES].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["VELOCITY"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["MASS"] = ShaderLanguage::TYPE_FLOAT;
- shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["ACTIVE"] = ShaderLanguage::TYPE_BOOL;
- shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["RESTART"] = constt(ShaderLanguage::TYPE_BOOL);
- shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["CUSTOM"] = ShaderLanguage::TYPE_VEC4;
- shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["TRANSFORM"] = ShaderLanguage::TYPE_MAT4;
- shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["DELTA"] = constt(ShaderLanguage::TYPE_FLOAT);
- shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_INT);
- shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
- shader_modes[RS::SHADER_PARTICLES].functions["vertex"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
- shader_modes[RS::SHADER_PARTICLES].functions["vertex"].can_discard = false;
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["COLOR"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["VELOCITY"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["MASS"] = ShaderLanguage::TYPE_FLOAT;
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["ACTIVE"] = ShaderLanguage::TYPE_BOOL;
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["CUSTOM"] = ShaderLanguage::TYPE_VEC4;
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["TRANSFORM"] = ShaderLanguage::TYPE_MAT4;
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["DELTA"] = constt(ShaderLanguage::TYPE_FLOAT);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["NUMBER"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_INT);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_POSITION"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_ROT_SCALE"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_VELOCITY"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_COLOR"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["FLAG_EMIT_CUSTOM"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_POSITION"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_ROT_SCALE"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_VELOCITY"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_COLOR"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].built_ins["RESTART_CUSTOM"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].can_discard = false;
+
+ {
+ ShaderLanguage::StageFunctionInfo emit_vertex_func;
+ emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("xform", ShaderLanguage::TYPE_MAT4));
+ emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("velocity", ShaderLanguage::TYPE_VEC3));
+ emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("color", ShaderLanguage::TYPE_VEC4));
+ emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("custom", ShaderLanguage::TYPE_VEC4));
+ emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("flags", ShaderLanguage::TYPE_UINT));
+ emit_vertex_func.return_type = ShaderLanguage::TYPE_BOOL; //whether it could emit
+ shader_modes[RS::SHADER_PARTICLES].functions["compute"].stage_functions["emit_particle"] = emit_vertex_func;
+ }
shader_modes[RS::SHADER_PARTICLES].modes.push_back("disable_force");
shader_modes[RS::SHADER_PARTICLES].modes.push_back("disable_velocity");
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 3b034da3aa..8f863a6fc8 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -2387,6 +2387,7 @@ RenderingServer::RenderingServer() {
GLOBAL_DEF("rendering/quality/glow/upscale_mode", 1);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/glow/upscale_mode", PropertyInfo(Variant::INT, "rendering/quality/glow/upscale_mode", PROPERTY_HINT_ENUM, "Linear (Fast),Bicubic (Slow)"));
GLOBAL_DEF("rendering/quality/glow/upscale_mode.mobile", 0);
+ GLOBAL_DEF("rendering/quality/glow/use_high_quality", false);
GLOBAL_DEF("rendering/quality/screen_space_reflection/roughness_quality", 1);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_space_reflection/roughness_quality", PropertyInfo(Variant::INT, "rendering/quality/screen_space_reflection/roughness_quality", PROPERTY_HINT_ENUM, "Disabled (Fastest),Low (Fast),Medium (Average),High (Slow)"));
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index a13fd4954b..64fa06ae72 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -563,7 +563,7 @@ public:
virtual RID particles_create() = 0;
- virtual void particles_set_emitting(RID p_particles, bool p_emitting) = 0;
+ virtual void particles_set_emitting(RID p_particles, bool p_enable) = 0;
virtual bool particles_get_emitting(RID p_particles) = 0;
virtual void particles_set_amount(RID p_particles, int p_amount) = 0;
virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0;
@@ -581,6 +581,18 @@ public:
virtual void particles_request_process(RID p_particles) = 0;
virtual void particles_restart(RID p_particles) = 0;
+ virtual void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) = 0;
+
+ enum ParticlesEmitFlags {
+ PARTICLES_EMIT_FLAG_POSITION = 1,
+ PARTICLES_EMIT_FLAG_ROTATION_SCALE = 2,
+ PARTICLES_EMIT_FLAG_VELOCITY = 4,
+ PARTICLES_EMIT_FLAG_COLOR = 8,
+ PARTICLES_EMIT_FLAG_CUSTOM = 16
+ };
+
+ virtual void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) = 0;
+
enum ParticlesDrawOrder {
PARTICLES_DRAW_ORDER_INDEX,
PARTICLES_DRAW_ORDER_LIFETIME,
@@ -784,6 +796,7 @@ public:
virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) = 0;
virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0;
+ virtual void environment_glow_set_use_high_quality(bool p_enable) = 0;
enum EnvironmentToneMapper {
ENV_TONE_MAPPER_LINEAR,
@@ -871,7 +884,7 @@ public:
ENV_VOLUMETRIC_FOG_SHADOW_FILTER_HIGH,
};
- virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_lenght, float p_detail_spread, float p_gi_inject, EnvVolumetricFogShadowFilter p_shadow_filter) = 0;
+ virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, EnvVolumetricFogShadowFilter p_shadow_filter) = 0;
virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0;
virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0;
virtual void environment_set_volumetric_fog_directional_shadow_shrink_size(int p_shrink_size) = 0;
diff --git a/servers/text_server.h b/servers/text_server.h
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/servers/text_server.h
diff --git a/tests/SCsub b/tests/SCsub
index 84c9fc1ffe..44b4cdc4b0 100644
--- a/tests/SCsub
+++ b/tests/SCsub
@@ -6,8 +6,8 @@ env.tests_sources = []
env_tests = env.Clone()
-# Enable test framework and inform it of configuration method.
-env_tests.Append(CPPDEFINES=["DOCTEST_CONFIG_IMPLEMENT"])
+# Include GDNative headers.
+env_tests.Append(CPPPATH=["#modules/gdnative/include"])
# We must disable the THREAD_LOCAL entirely in doctest to prevent crashes on debugging
# Since we link with /MT thread_local is always expired when the header is used
diff --git a/tests/test_color.h b/tests/test_color.h
index 3633f2746d..dfdc29ec7d 100644
--- a/tests/test_color.h
+++ b/tests/test_color.h
@@ -39,9 +39,7 @@ namespace TestColor {
TEST_CASE("[Color] Constructor methods") {
const Color blue_rgba = Color(0.25098, 0.376471, 1, 0.501961);
- // HTML currently uses ARGB notation, which is contrary to the CSS standard.
- // This may be changed to RGBA in 4.0.
- const Color blue_html = Color::html("#804060ff");
+ const Color blue_html = Color::html("#4060ff80");
const Color blue_hex = Color::hex(0x4060ff80);
const Color blue_hex64 = Color::hex64(0x4040'6060'ffff'8080);
@@ -118,10 +116,10 @@ TEST_CASE("[Color] Conversion methods") {
const Color cyan_transparent = Color(0, 1, 1, 0);
CHECK_MESSAGE(
- cyan.to_html() == "ff00ffff",
+ cyan.to_html() == "00ffffff",
"The returned RGB HTML color code should match the expected value.");
CHECK_MESSAGE(
- cyan_transparent.to_html() == "0000ffff",
+ cyan_transparent.to_html() == "00ffff00",
"The returned RGBA HTML color code should match the expected value.");
CHECK_MESSAGE(
cyan.to_argb32() == 0xff00ffff,
diff --git a/tests/test_expression.h b/tests/test_expression.h
new file mode 100644
index 0000000000..85d37d1460
--- /dev/null
+++ b/tests/test_expression.h
@@ -0,0 +1,431 @@
+/*************************************************************************/
+/* test_expression.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_EXPRESSION_H
+#define TEST_EXPRESSION_H
+
+#include "core/math/expression.h"
+
+#include "tests/test_macros.h"
+
+namespace TestExpression {
+
+TEST_CASE("[Expression] Integer arithmetic") {
+ Expression expression;
+
+ CHECK_MESSAGE(
+ expression.parse("-123456") == OK,
+ "Integer identity should parse successfully.");
+ CHECK_MESSAGE(
+ int(expression.execute()) == -123456,
+ "Integer identity should return the expected result.");
+
+ CHECK_MESSAGE(
+ expression.parse("2 + 3") == OK,
+ "Integer addition should parse successfully.");
+ CHECK_MESSAGE(
+ int(expression.execute()) == 5,
+ "Integer addition should return the expected result.");
+
+ CHECK_MESSAGE(
+ expression.parse("999999999999 + 999999999999") == OK,
+ "Large integer addition should parse successfully.");
+ CHECK_MESSAGE(
+ int64_t(expression.execute()) == 1'999'999'999'998,
+ "Large integer addition should return the expected result.");
+
+ CHECK_MESSAGE(
+ expression.parse("25 / 10") == OK,
+ "Integer / integer division should parse successfully.");
+ CHECK_MESSAGE(
+ int(expression.execute()) == 2,
+ "Integer / integer divsion should return the expected result.");
+
+ CHECK_MESSAGE(
+ expression.parse("2 * (6 + 14) / 2 - 5") == OK,
+ "Integer multiplication-addition-subtraction-division should parse successfully.");
+ CHECK_MESSAGE(
+ int(expression.execute()) == 15,
+ "Integer multiplication-addition-subtraction-division should return the expected result.");
+}
+
+TEST_CASE("[Expression] Floating-point arithmetic") {
+ Expression expression;
+
+ CHECK_MESSAGE(
+ expression.parse("-123.456") == OK,
+ "Float identity should parse successfully.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(float(expression.execute()), -123.456),
+ "Float identity should return the expected result.");
+
+ CHECK_MESSAGE(
+ expression.parse("2.0 + 3.0") == OK,
+ "Float addition should parse successfully.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(float(expression.execute()), 5),
+ "Float addition should return the expected result.");
+
+ CHECK_MESSAGE(
+ expression.parse("3.0 / 10") == OK,
+ "Float / integer division should parse successfully.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(float(expression.execute()), 0.3),
+ "Float / integer divsion should return the expected result.");
+
+ CHECK_MESSAGE(
+ expression.parse("3 / 10.0") == OK,
+ "Basic integer / float division should parse successfully.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(float(expression.execute()), 0.3),
+ "Basic integer / float divsion should return the expected result.");
+
+ CHECK_MESSAGE(
+ expression.parse("3.0 / 10.0") == OK,
+ "Float / float division should parse successfully.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(float(expression.execute()), 0.3),
+ "Float / float divsion should return the expected result.");
+
+ CHECK_MESSAGE(
+ expression.parse("2.5 * (6.0 + 14.25) / 2.0 - 5.12345") == OK,
+ "Float multiplication-addition-subtraction-division should parse successfully.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(float(expression.execute()), 20.18905),
+ "Float multiplication-addition-subtraction-division should return the expected result.");
+}
+
+TEST_CASE("[Expression] Scientific notation") {
+ Expression expression;
+
+ CHECK_MESSAGE(
+ expression.parse("2.e5") == OK,
+ "The expression should parse successfully.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(float(expression.execute()), 200'000),
+ "The expression should return the expected result.");
+
+ // The middle "e" is ignored here.
+ CHECK_MESSAGE(
+ expression.parse("2e5") == OK,
+ "The expression should parse successfully.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(float(expression.execute()), 25),
+ "The expression should return the expected result.");
+
+ CHECK_MESSAGE(
+ expression.parse("2e.5") == OK,
+ "The expression should parse successfully.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(float(expression.execute()), 2),
+ "The expression should return the expected result.");
+}
+
+TEST_CASE("[Expression] Built-in functions") {
+ Expression expression;
+
+ CHECK_MESSAGE(
+ expression.parse("sqrt(pow(3, 2) + pow(4, 2))") == OK,
+ "The expression should parse successfully.");
+ CHECK_MESSAGE(
+ int(expression.execute()) == 5,
+ "`sqrt(pow(3, 2) + pow(4, 2))` should return the expected result.");
+
+ CHECK_MESSAGE(
+ expression.parse("stepify(sin(0.5), 0.01)") == OK,
+ "The expression should parse successfully.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(float(expression.execute()), 0.48),
+ "`stepify(sin(0.5), 0.01)` should return the expected result.");
+
+ CHECK_MESSAGE(
+ expression.parse("pow(2.0, -2500)") == OK,
+ "The expression should parse successfully.");
+ CHECK_MESSAGE(
+ Math::is_zero_approx(float(expression.execute())),
+ "`pow(2.0, -2500)` should return the expected result (asymptotically zero).");
+}
+
+TEST_CASE("[Expression] Boolean expressions") {
+ Expression expression;
+
+ CHECK_MESSAGE(
+ expression.parse("24 >= 12") == OK,
+ "The boolean expression should parse successfully.");
+ CHECK_MESSAGE(
+ bool(expression.execute()),
+ "The boolean expression should evaluate to `true`.");
+
+ CHECK_MESSAGE(
+ expression.parse("1.0 < 1.25 && 1.25 < 2.0") == OK,
+ "The boolean expression should parse successfully.");
+ CHECK_MESSAGE(
+ bool(expression.execute()),
+ "The boolean expression should evaluate to `true`.");
+
+ CHECK_MESSAGE(
+ expression.parse("!2") == OK,
+ "The boolean expression should parse successfully.");
+ CHECK_MESSAGE(
+ !bool(expression.execute()),
+ "The boolean expression should evaluate to `false`.");
+
+ CHECK_MESSAGE(
+ expression.parse("!!2") == OK,
+ "The boolean expression should parse successfully.");
+ CHECK_MESSAGE(
+ bool(expression.execute()),
+ "The boolean expression should evaluate to `true`.");
+
+ CHECK_MESSAGE(
+ expression.parse("!0") == OK,
+ "The boolean expression should parse successfully.");
+ CHECK_MESSAGE(
+ bool(expression.execute()),
+ "The boolean expression should evaluate to `true`.");
+
+ CHECK_MESSAGE(
+ expression.parse("!!0") == OK,
+ "The boolean expression should parse successfully.");
+ CHECK_MESSAGE(
+ !bool(expression.execute()),
+ "The boolean expression should evaluate to `false`.");
+
+ CHECK_MESSAGE(
+ expression.parse("2 && 5") == OK,
+ "The boolean expression should parse successfully.");
+ CHECK_MESSAGE(
+ bool(expression.execute()),
+ "The boolean expression should evaluate to `true`.");
+
+ CHECK_MESSAGE(
+ expression.parse("0 || 0") == OK,
+ "The boolean expression should parse successfully.");
+ CHECK_MESSAGE(
+ !bool(expression.execute()),
+ "The boolean expression should evaluate to `false`.");
+
+ CHECK_MESSAGE(
+ expression.parse("(2 <= 4) && (2 > 5)") == OK,
+ "The boolean expression should parse successfully.");
+ CHECK_MESSAGE(
+ !bool(expression.execute()),
+ "The boolean expression should evaluate to `false`.");
+}
+
+TEST_CASE("[Expression] Expressions with variables") {
+ Expression expression;
+
+ PackedStringArray parameter_names;
+ parameter_names.push_back("foo");
+ parameter_names.push_back("bar");
+ CHECK_MESSAGE(
+ expression.parse("foo + bar + 50", parameter_names) == OK,
+ "The expression should parse successfully.");
+ Array values;
+ values.push_back(60);
+ values.push_back(20);
+ CHECK_MESSAGE(
+ int(expression.execute(values)) == 130,
+ "The expression should return the expected value.");
+
+ PackedStringArray parameter_names_invalid;
+ parameter_names_invalid.push_back("foo");
+ parameter_names_invalid.push_back("baz"); // Invalid parameter name.
+ CHECK_MESSAGE(
+ expression.parse("foo + bar + 50", parameter_names_invalid) == OK,
+ "The expression should parse successfully.");
+ Array values_invalid;
+ values_invalid.push_back(60);
+ values_invalid.push_back(20);
+ // Invalid parameters will parse successfully but print an error message when executing.
+ ERR_PRINT_OFF;
+ CHECK_MESSAGE(
+ int(expression.execute(values_invalid)) == 0,
+ "The expression should return the expected value.");
+ ERR_PRINT_ON;
+
+ // Mismatched argument count (more values than parameters).
+ PackedStringArray parameter_names_mismatch;
+ parameter_names_mismatch.push_back("foo");
+ parameter_names_mismatch.push_back("bar");
+ CHECK_MESSAGE(
+ expression.parse("foo + bar + 50", parameter_names_mismatch) == OK,
+ "The expression should parse successfully.");
+ Array values_mismatch;
+ values_mismatch.push_back(60);
+ values_mismatch.push_back(20);
+ values_mismatch.push_back(110);
+ CHECK_MESSAGE(
+ int(expression.execute(values_mismatch)) == 130,
+ "The expression should return the expected value.");
+
+ // Mismatched argument count (more parameters than values).
+ PackedStringArray parameter_names_mismatch2;
+ parameter_names_mismatch2.push_back("foo");
+ parameter_names_mismatch2.push_back("bar");
+ parameter_names_mismatch2.push_back("baz");
+ CHECK_MESSAGE(
+ expression.parse("foo + bar + baz + 50", parameter_names_mismatch2) == OK,
+ "The expression should parse successfully.");
+ Array values_mismatch2;
+ values_mismatch2.push_back(60);
+ values_mismatch2.push_back(20);
+ // Having more parameters than values will parse successfully but print an
+ // error message when executing.
+ ERR_PRINT_OFF;
+ CHECK_MESSAGE(
+ int(expression.execute(values_mismatch2)) == 0,
+ "The expression should return the expected value.");
+ ERR_PRINT_ON;
+}
+
+TEST_CASE("[Expression] Invalid expressions") {
+ Expression expression;
+
+ CHECK_MESSAGE(
+ expression.parse("\\") == ERR_INVALID_PARAMETER,
+ "The expression shouldn't parse successfully.");
+
+ CHECK_MESSAGE(
+ expression.parse("0++") == ERR_INVALID_PARAMETER,
+ "The expression shouldn't parse successfully.");
+
+ CHECK_MESSAGE(
+ expression.parse("()") == ERR_INVALID_PARAMETER,
+ "The expression shouldn't parse successfully.");
+
+ CHECK_MESSAGE(
+ expression.parse("()()") == ERR_INVALID_PARAMETER,
+ "The expression shouldn't parse successfully.");
+
+ CHECK_MESSAGE(
+ expression.parse("() - ()") == ERR_INVALID_PARAMETER,
+ "The expression shouldn't parse successfully.");
+
+ CHECK_MESSAGE(
+ expression.parse("() * 12345") == ERR_INVALID_PARAMETER,
+ "The expression shouldn't parse successfully.");
+
+ CHECK_MESSAGE(
+ expression.parse("() * 12345") == ERR_INVALID_PARAMETER,
+ "The expression shouldn't parse successfully.");
+
+ CHECK_MESSAGE(
+ expression.parse("123'456") == ERR_INVALID_PARAMETER,
+ "The expression shouldn't parse successfully.");
+
+ CHECK_MESSAGE(
+ expression.parse("123\"456") == ERR_INVALID_PARAMETER,
+ "The expression shouldn't parse successfully.");
+}
+
+TEST_CASE("[Expression] Unusual expressions") {
+ Expression expression;
+
+ // Redundant parentheses don't cause a parse error as long as they're matched.
+ CHECK_MESSAGE(
+ expression.parse("(((((((((((((((666)))))))))))))))") == OK,
+ "The expression should parse successfully.");
+
+ // Using invalid identifiers doesn't cause a parse error.
+ ERR_PRINT_OFF;
+ CHECK_MESSAGE(
+ expression.parse("hello + hello") == OK,
+ "The expression should parse successfully.");
+ CHECK_MESSAGE(
+ int(expression.execute()) == 0,
+ "The expression should return the expected result.");
+ ERR_PRINT_ON;
+
+ ERR_PRINT_OFF;
+ CHECK_MESSAGE(
+ expression.parse("$1.00 + €5") == OK,
+ "The expression should parse successfully.");
+ CHECK_MESSAGE(
+ int(expression.execute()) == 0,
+ "The expression should return the expected result.");
+ ERR_PRINT_ON;
+
+ // Commas can't be used as a decimal parameter.
+ CHECK_MESSAGE(
+ expression.parse("123,456") == OK,
+ "The expression should parse successfully.");
+ CHECK_MESSAGE(
+ int(expression.execute()) == 123,
+ "The expression should return the expected result.");
+
+ // Spaces can't be used as a separator for large numbers.
+ CHECK_MESSAGE(
+ expression.parse("123 456") == OK,
+ "The expression should parse successfully.");
+ CHECK_MESSAGE(
+ int(expression.execute()) == 123,
+ "The expression should return the expected result.");
+
+ // Division by zero is accepted, even though it prints an error message normally.
+ CHECK_MESSAGE(
+ expression.parse("-25.4 / 0") == OK,
+ "The expression should parse successfully.");
+ ERR_PRINT_OFF;
+ CHECK_MESSAGE(
+ Math::is_zero_approx(float(expression.execute())),
+ "`-25.4 / 0` should return 0.");
+ ERR_PRINT_ON;
+
+ CHECK_MESSAGE(
+ expression.parse("0 / 0") == OK,
+ "The expression should parse successfully.");
+ ERR_PRINT_OFF;
+ CHECK_MESSAGE(
+ int(expression.execute()) == 0,
+ "`0 / 0` should return 0.");
+ ERR_PRINT_ON;
+
+ // The tests below currently crash the engine.
+ //
+ //CHECK_MESSAGE(
+ // expression.parse("(-9223372036854775807 - 1) % -1") == OK,
+ // "The expression should parse successfully.");
+ //CHECK_MESSAGE(
+ // int64_t(expression.execute()) == 0,
+ // "`(-9223372036854775807 - 1) % -1` should return the expected result.");
+ //
+ //CHECK_MESSAGE(
+ // expression.parse("(-9223372036854775807 - 1) / -1") == OK,
+ // "The expression should parse successfully.");
+ //CHECK_MESSAGE(
+ // int64_t(expression.execute()) == 0,
+ // "`(-9223372036854775807 - 1) / -1` should return the expected result.");
+}
+
+} // namespace TestExpression
+
+#endif // TEST_EXPRESSION_H
diff --git a/tests/test_gdnative_string.h b/tests/test_gdnative_string.h
new file mode 100644
index 0000000000..76868ba842
--- /dev/null
+++ b/tests/test_gdnative_string.h
@@ -0,0 +1,1985 @@
+/*************************************************************************/
+/* test_gdnative_string.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_GDNATVIE_STRING_H
+#define TEST_GDNATVIE_STRING_H
+
+namespace TestGDNativeString {
+
+#include "modules/modules_enabled.gen.h"
+#ifdef MODULE_GDNATIVE_ENABLED
+
+#include "gdnative/string.h"
+
+#include "tests/test_macros.h"
+
+int u32scmp(const char32_t *l, const char32_t *r) {
+ for (; *l == *r && *l && *r; l++, r++)
+ ;
+ return *l - *r;
+}
+
+TEST_CASE("[GDNatvie String] Construct from Latin-1 char string") {
+ godot_string s;
+
+ godot_string_new_with_latin1_chars(&s, "Hello");
+ CHECK(u32scmp(godot_string_get_data(&s), U"Hello") == 0);
+ godot_string_destroy(&s);
+
+ godot_string_new_with_latin1_chars_and_len(&s, "Hello", 3);
+ CHECK(u32scmp(godot_string_get_data(&s), U"Hel") == 0);
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Construct from wchar_t string") {
+ godot_string s;
+
+ godot_string_new_with_wide_chars(&s, L"Give me");
+ CHECK(u32scmp(godot_string_get_data(&s), U"Give me") == 0);
+ godot_string_destroy(&s);
+
+ godot_string_new_with_wide_chars_and_len(&s, L"Give me", 3);
+ CHECK(u32scmp(godot_string_get_data(&s), U"Giv") == 0);
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Construct from UTF-8 char string") {
+ static const char32_t u32str[] = { 0x0045, 0x0020, 0x304A, 0x360F, 0x3088, 0x3046, 0x1F3A4, 0 };
+ static const char32_t u32str_short[] = { 0x0045, 0x0020, 0x304A, 0 };
+ static const uint8_t u8str[] = { 0x45, 0x20, 0xE3, 0x81, 0x8A, 0xE3, 0x98, 0x8F, 0xE3, 0x82, 0x88, 0xE3, 0x81, 0x86, 0xF0, 0x9F, 0x8E, 0xA4, 0 };
+
+ godot_string s;
+
+ godot_string_new_with_utf8_chars(&s, (const char *)u8str);
+ CHECK(u32scmp(godot_string_get_data(&s), u32str) == 0);
+ godot_string_destroy(&s);
+
+ godot_string_new_with_utf8_chars_and_len(&s, (const char *)u8str, 5);
+ CHECK(u32scmp(godot_string_get_data(&s), u32str_short) == 0);
+ godot_string_destroy(&s);
+
+ godot_string_new_with_utf32_chars(&s, u32str);
+ godot_char_string cs = godot_string_utf8(&s);
+ godot_string_parse_utf8(&s, godot_char_string_get_data(&cs));
+ CHECK(u32scmp(godot_string_get_data(&s), u32str) == 0);
+ godot_string_destroy(&s);
+ godot_char_string_destroy(&cs);
+
+ godot_string_new_with_utf32_chars(&s, u32str);
+ cs = godot_string_utf8(&s);
+ godot_string_parse_utf8_with_len(&s, godot_char_string_get_data(&cs), godot_char_string_length(&cs));
+ CHECK(u32scmp(godot_string_get_data(&s), u32str) == 0);
+ godot_string_destroy(&s);
+ godot_char_string_destroy(&cs);
+}
+
+TEST_CASE("[GDNatvie String] Construct from UTF-8 string with BOM") {
+ static const char32_t u32str[] = { 0x0045, 0x0020, 0x304A, 0x360F, 0x3088, 0x3046, 0x1F3A4, 0 };
+ static const char32_t u32str_short[] = { 0x0045, 0x0020, 0x304A, 0 };
+ static const uint8_t u8str[] = { 0xEF, 0xBB, 0xBF, 0x45, 0x20, 0xE3, 0x81, 0x8A, 0xE3, 0x98, 0x8F, 0xE3, 0x82, 0x88, 0xE3, 0x81, 0x86, 0xF0, 0x9F, 0x8E, 0xA4, 0 };
+
+ godot_string s;
+
+ godot_string_new_with_utf8_chars(&s, (const char *)u8str);
+ CHECK(u32scmp(godot_string_get_data(&s), u32str) == 0);
+ godot_string_destroy(&s);
+
+ godot_string_new_with_utf8_chars_and_len(&s, (const char *)u8str, 8);
+ CHECK(u32scmp(godot_string_get_data(&s), u32str_short) == 0);
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Construct from UTF-16 string") {
+ static const char32_t u32str[] = { 0x0045, 0x0020, 0x1F3A4, 0x360F, 0x3088, 0x3046, 0x1F3A4, 0 };
+ static const char32_t u32str_short[] = { 0x0045, 0x0020, 0x1F3A4, 0 };
+ static const char16_t u16str[] = { 0x0045, 0x0020, 0xD83C, 0xDFA4, 0x360F, 0x3088, 0x3046, 0xD83C, 0xDFA4, 0 };
+
+ godot_string s;
+
+ godot_string_new_with_utf16_chars(&s, u16str);
+ CHECK(u32scmp(godot_string_get_data(&s), u32str) == 0);
+ godot_string_destroy(&s);
+
+ godot_string_new_with_utf16_chars_and_len(&s, u16str, 4);
+ CHECK(u32scmp(godot_string_get_data(&s), u32str_short) == 0);
+ godot_string_destroy(&s);
+
+ godot_string_new_with_utf32_chars(&s, u32str);
+ godot_char16_string cs = godot_string_utf16(&s);
+ godot_string_parse_utf16(&s, godot_char16_string_get_data(&cs));
+ CHECK(u32scmp(godot_string_get_data(&s), u32str) == 0);
+ godot_string_destroy(&s);
+ godot_char16_string_destroy(&cs);
+
+ godot_string_new_with_utf32_chars(&s, u32str);
+ cs = godot_string_utf16(&s);
+ godot_string_parse_utf16_with_len(&s, godot_char16_string_get_data(&cs), godot_char16_string_length(&cs));
+ CHECK(u32scmp(godot_string_get_data(&s), u32str) == 0);
+ godot_string_destroy(&s);
+ godot_char16_string_destroy(&cs);
+}
+
+TEST_CASE("[GDNatvie String] Construct from UTF-16 string with BOM ") {
+ static const char32_t u32str[] = { 0x0045, 0x0020, 0x1F3A4, 0x360F, 0x3088, 0x3046, 0x1F3A4, 0 };
+ static const char32_t u32str_short[] = { 0x0045, 0x0020, 0x1F3A4, 0 };
+ static const char16_t u16str[] = { 0xFEFF, 0x0045, 0x0020, 0xD83C, 0xDFA4, 0x360F, 0x3088, 0x3046, 0xD83C, 0xDFA4, 0 };
+ static const char16_t u16str_swap[] = { 0xFFFE, 0x4500, 0x2000, 0x3CD8, 0xA4DF, 0x0F36, 0x8830, 0x4630, 0x3CD8, 0xA4DF, 0 };
+
+ godot_string s;
+
+ godot_string_new_with_utf16_chars(&s, u16str);
+ CHECK(u32scmp(godot_string_get_data(&s), u32str) == 0);
+ godot_string_destroy(&s);
+
+ godot_string_new_with_utf16_chars(&s, u16str_swap);
+ CHECK(u32scmp(godot_string_get_data(&s), u32str) == 0);
+ godot_string_destroy(&s);
+
+ godot_string_new_with_utf16_chars_and_len(&s, u16str, 5);
+ CHECK(u32scmp(godot_string_get_data(&s), u32str_short) == 0);
+ godot_string_destroy(&s);
+
+ godot_string_new_with_utf16_chars_and_len(&s, u16str_swap, 5);
+ CHECK(u32scmp(godot_string_get_data(&s), u32str_short) == 0);
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Construct string copy") {
+ godot_string s, t;
+
+ godot_string_new_with_latin1_chars(&s, "Hello");
+ godot_string_new_copy(&t, &s);
+ CHECK(u32scmp(godot_string_get_data(&t), U"Hello") == 0);
+ godot_string_destroy(&t);
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Construct empty string") {
+ godot_string s;
+
+ godot_string_new(&s);
+ CHECK(u32scmp(godot_string_get_data(&s), U"") == 0);
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] ASCII/Latin-1") {
+ godot_string s;
+ godot_string_new_with_utf32_chars(&s, U"Primero Leche");
+
+ godot_char_string cs = godot_string_ascii(&s);
+ CHECK(strcmp(godot_char_string_get_data(&cs), "Primero Leche") == 0);
+ godot_char_string_destroy(&cs);
+
+ cs = godot_string_latin1(&s);
+ CHECK(strcmp(godot_char_string_get_data(&cs), "Primero Leche") == 0);
+ godot_char_string_destroy(&cs);
+
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Comparisons (equal)") {
+ godot_string s, t;
+
+ godot_string_new_with_latin1_chars(&s, "Test Compare");
+ godot_string_new_with_latin1_chars(&t, "Test Compare");
+ CHECK(godot_string_operator_equal(&s, &t));
+ godot_string_destroy(&s);
+ godot_string_destroy(&t);
+}
+
+TEST_CASE("[GDNatvie String] Comparisons (operator <)") {
+ godot_string s, t;
+
+ godot_string_new_with_latin1_chars(&s, "Bees");
+
+ godot_string_new_with_latin1_chars(&t, "Elephant");
+ CHECK(godot_string_operator_less(&s, &t));
+ godot_string_destroy(&t);
+
+ godot_string_new_with_latin1_chars(&t, "Amber");
+ CHECK(!godot_string_operator_less(&s, &t));
+ godot_string_destroy(&t);
+
+ godot_string_new_with_latin1_chars(&t, "Beatrix");
+ CHECK(!godot_string_operator_less(&s, &t));
+ godot_string_destroy(&t);
+
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Concatenation (operator +)") {
+ godot_string s, t, x;
+
+ godot_string_new_with_latin1_chars(&s, "Hel");
+ godot_string_new_with_latin1_chars(&t, "lo");
+ x = godot_string_operator_plus(&s, &t);
+ CHECK(u32scmp(godot_string_get_data(&x), U"Hello") == 0);
+ godot_string_destroy(&x);
+ godot_string_destroy(&s);
+ godot_string_destroy(&t);
+}
+
+TEST_CASE("[GDNatvie String] Testing size and length of string") {
+ godot_string s;
+
+ godot_string_new_with_latin1_chars(&s, "Mellon");
+ CHECK(godot_string_length(&s) == 6);
+ godot_string_destroy(&s);
+
+ godot_string_new_with_latin1_chars(&s, "Mellon1");
+ CHECK(godot_string_length(&s) == 7);
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Testing for empty string") {
+ godot_string s;
+
+ godot_string_new_with_latin1_chars(&s, "Mellon");
+ CHECK(!godot_string_empty(&s));
+ godot_string_destroy(&s);
+
+ godot_string_new_with_latin1_chars(&s, "");
+ CHECK(godot_string_empty(&s));
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Test chr") {
+ godot_string s;
+
+ s = godot_string_chr('H');
+ CHECK(u32scmp(godot_string_get_data(&s), U"H") == 0);
+ godot_string_destroy(&s);
+
+ s = godot_string_chr(0x3012);
+ CHECK(godot_string_operator_index_const(&s, 0) == 0x3012);
+ godot_string_destroy(&s);
+
+ ERR_PRINT_OFF
+ s = godot_string_chr(0xd812);
+ CHECK(godot_string_operator_index_const(&s, 0) == 0xfffd); // Unpaired UTF-16 surrogate
+ godot_string_destroy(&s);
+
+ s = godot_string_chr(0x20d812);
+ CHECK(godot_string_operator_index_const(&s, 0) == 0xfffd); // Outside UTF-32 range
+ godot_string_destroy(&s);
+ ERR_PRINT_ON
+}
+
+TEST_CASE("[GDNatvie String] Operator []") {
+ godot_string s;
+
+ godot_string_new_with_latin1_chars(&s, "Hello");
+ CHECK(*godot_string_operator_index(&s, 1) == 'e');
+ CHECK(godot_string_operator_index_const(&s, 0) == 'H');
+ CHECK(godot_string_ord_at(&s, 0) == 'H');
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Case function test") {
+ godot_string s, t;
+
+ godot_string_new_with_latin1_chars(&s, "MoMoNgA");
+
+ t = godot_string_to_upper(&s);
+ CHECK(u32scmp(godot_string_get_data(&t), U"MOMONGA") == 0);
+ godot_string_destroy(&t);
+
+ t = godot_string_to_lower(&s);
+ CHECK(u32scmp(godot_string_get_data(&t), U"momonga") == 0);
+ godot_string_destroy(&t);
+
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Case compare function test") {
+ godot_string s, t;
+
+ godot_string_new_with_latin1_chars(&s, "MoMoNgA");
+ godot_string_new_with_latin1_chars(&t, "momonga");
+
+ CHECK(godot_string_casecmp_to(&s, &t) != 0);
+ CHECK(godot_string_nocasecmp_to(&s, &t) == 0);
+
+ godot_string_destroy(&s);
+ godot_string_destroy(&t);
+}
+
+TEST_CASE("[GDNatvie String] Natural compare function test") {
+ godot_string s, t;
+
+ godot_string_new_with_latin1_chars(&s, "img2.png");
+ godot_string_new_with_latin1_chars(&t, "img10.png");
+
+ CHECK(godot_string_nocasecmp_to(&s, &t) > 0);
+ CHECK(godot_string_naturalnocasecmp_to(&s, &t) < 0);
+
+ godot_string_destroy(&s);
+ godot_string_destroy(&t);
+}
+
+TEST_CASE("[GDNatvie String] hex_encode_buffer") {
+ static const uint8_t u8str[] = { 0x45, 0xE3, 0x81, 0x8A, 0x8F, 0xE3 };
+ godot_string s = godot_string_hex_encode_buffer(u8str, 6);
+ CHECK(u32scmp(godot_string_get_data(&s), U"45e3818a8fe3") == 0);
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Substr") {
+ godot_string s, t;
+ godot_string_new_with_latin1_chars(&s, "Killer Baby");
+ t = godot_string_substr(&s, 3, 4);
+ CHECK(u32scmp(godot_string_get_data(&t), U"ler ") == 0);
+ godot_string_destroy(&t);
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Find") {
+ godot_string s, t;
+ godot_string_new_with_latin1_chars(&s, "Pretty Woman Woman");
+
+ godot_string_new_with_latin1_chars(&t, "Revenge of the Monster Truck");
+ CHECK(godot_string_find(&s, &t) == -1);
+ godot_string_destroy(&t);
+
+ godot_string_new_with_latin1_chars(&t, "tty");
+ CHECK(godot_string_find(&s, &t) == 3);
+ godot_string_destroy(&t);
+
+ godot_string_new_with_latin1_chars(&t, "Wo");
+ CHECK(godot_string_find_from(&s, &t, 9) == 13);
+ godot_string_destroy(&t);
+
+ godot_string_new_with_latin1_chars(&t, "man");
+ CHECK(godot_string_rfind(&s, &t) == 15);
+ godot_string_destroy(&t);
+
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Find no case") {
+ godot_string s, t;
+ godot_string_new_with_latin1_chars(&s, "Pretty Whale Whale");
+
+ godot_string_new_with_latin1_chars(&t, "WHA");
+ CHECK(godot_string_findn(&s, &t) == 7);
+ godot_string_destroy(&t);
+
+ godot_string_new_with_latin1_chars(&t, "WHA");
+ CHECK(godot_string_findn_from(&s, &t, 9) == 13);
+ godot_string_destroy(&t);
+
+ godot_string_new_with_latin1_chars(&t, "WHA");
+ CHECK(godot_string_rfindn(&s, &t) == 13);
+ godot_string_destroy(&t);
+
+ godot_string_new_with_latin1_chars(&t, "Revenge of the Monster SawFish");
+ CHECK(godot_string_findn(&s, &t) == -1);
+ godot_string_destroy(&t);
+
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Find MK") {
+ godot_packed_string_array keys;
+ godot_packed_string_array_new(&keys);
+
+#define PUSH_KEY(x) \
+ { \
+ godot_string t; \
+ godot_string_new_with_latin1_chars(&t, x); \
+ godot_packed_string_array_push_back(&keys, &t); \
+ godot_string_destroy(&t); \
+ }
+
+ PUSH_KEY("sty")
+ PUSH_KEY("tty")
+ PUSH_KEY("man")
+
+ godot_string s;
+ godot_string_new_with_latin1_chars(&s, "Pretty Woman");
+ godot_int key = 0;
+
+ CHECK(godot_string_findmk(&s, &keys) == 3);
+ CHECK(godot_string_findmk_from_in_place(&s, &keys, 0, &key) == 3);
+ CHECK(key == 1);
+
+ CHECK(godot_string_findmk_from(&s, &keys, 5) == 9);
+ CHECK(godot_string_findmk_from_in_place(&s, &keys, 5, &key) == 9);
+ CHECK(key == 2);
+
+ godot_string_destroy(&s);
+ godot_packed_string_array_destroy(&keys);
+
+#undef PUSH_KEY
+}
+
+TEST_CASE("[GDNatvie String] Find and replace") {
+ godot_string s, c, w;
+ godot_string_new_with_latin1_chars(&s, "Happy Birthday, Anna!");
+ godot_string_new_with_latin1_chars(&c, "Birthday");
+ godot_string_new_with_latin1_chars(&w, "Halloween");
+ godot_string t = godot_string_replace(&s, &c, &w);
+ CHECK(u32scmp(godot_string_get_data(&t), U"Happy Halloween, Anna!") == 0);
+ godot_string_destroy(&s);
+ godot_string_destroy(&c);
+ godot_string_destroy(&w);
+
+ godot_string_new_with_latin1_chars(&c, "H");
+ godot_string_new_with_latin1_chars(&w, "W");
+ s = godot_string_replace_first(&t, &c, &w);
+ godot_string_destroy(&t);
+ godot_string_destroy(&c);
+ godot_string_destroy(&w);
+
+ CHECK(u32scmp(godot_string_get_data(&s), U"Wappy Halloween, Anna!") == 0);
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Insertion") {
+ godot_string s, t, r, u;
+ godot_string_new_with_latin1_chars(&s, "Who is Frederic?");
+ godot_string_new_with_latin1_chars(&t, "?");
+ godot_string_new_with_latin1_chars(&r, " Chopin");
+
+ u = godot_string_insert(&s, godot_string_find(&s, &t), &r);
+ CHECK(u32scmp(godot_string_get_data(&u), U"Who is Frederic Chopin?") == 0);
+
+ godot_string_destroy(&s);
+ godot_string_destroy(&t);
+ godot_string_destroy(&r);
+ godot_string_destroy(&u);
+}
+
+TEST_CASE("[GDNatvie String] Number to string") {
+ godot_string s;
+ s = godot_string_num(3.141593);
+ CHECK(u32scmp(godot_string_get_data(&s), U"3.141593") == 0);
+ godot_string_destroy(&s);
+
+ s = godot_string_num_with_decimals(3.141593, 3);
+ CHECK(u32scmp(godot_string_get_data(&s), U"3.142") == 0);
+ godot_string_destroy(&s);
+
+ s = godot_string_num_real(3.141593);
+ CHECK(u32scmp(godot_string_get_data(&s), U"3.141593") == 0);
+ godot_string_destroy(&s);
+
+ s = godot_string_num_scientific(30000000);
+ CHECK(u32scmp(godot_string_get_data(&s), U"3e+07") == 0);
+ godot_string_destroy(&s);
+
+ s = godot_string_num_int64(3141593, 10);
+ CHECK(u32scmp(godot_string_get_data(&s), U"3141593") == 0);
+ godot_string_destroy(&s);
+
+ s = godot_string_num_int64(0xA141593, 16);
+ CHECK(u32scmp(godot_string_get_data(&s), U"a141593") == 0);
+ godot_string_destroy(&s);
+
+ s = godot_string_num_int64_capitalized(0xA141593, 16, true);
+ CHECK(u32scmp(godot_string_get_data(&s), U"A141593") == 0);
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] String to integer") {
+ static const wchar_t *wnums[4] = { L"1237461283", L"- 22", L"0", L" - 1123412" };
+ static const char *nums[4] = { "1237461283", "- 22", "0", " - 1123412" };
+ static const int num[4] = { 1237461283, -22, 0, -1123412 };
+
+ for (int i = 0; i < 4; i++) {
+ godot_string s;
+ godot_string_new_with_latin1_chars(&s, nums[i]);
+ CHECK(godot_string_to_int(&s) == num[i]);
+ godot_string_destroy(&s);
+
+ CHECK(godot_string_char_to_int(nums[i]) == num[i]);
+ CHECK(godot_string_wchar_to_int(wnums[i]) == num[i]);
+ }
+}
+
+TEST_CASE("[GDNatvie String] Hex to integer") {
+ static const char *nums[4] = { "0xFFAE", "22", "0", "AADDAD" };
+ static const int64_t num[4] = { 0xFFAE, 0x22, 0, 0xAADDAD };
+ static const bool wo_prefix[4] = { false, true, true, true };
+ static const bool w_prefix[4] = { true, false, true, false };
+
+ for (int i = 0; i < 4; i++) {
+ godot_string s;
+ godot_string_new_with_latin1_chars(&s, nums[i]);
+ CHECK((godot_string_hex_to_int_with_prefix(&s) == num[i]) == w_prefix[i]);
+ CHECK((godot_string_hex_to_int(&s) == num[i]) == wo_prefix[i]);
+ godot_string_destroy(&s);
+ }
+}
+
+TEST_CASE("[GDNatvie String] String to float") {
+ static const wchar_t *wnums[4] = { L"-12348298412.2", L"0.05", L"2.0002", L" -0.0001" };
+ static const char *nums[4] = { "-12348298412.2", "0.05", "2.0002", " -0.0001" };
+ static const double num[4] = { -12348298412.2, 0.05, 2.0002, -0.0001 };
+
+ for (int i = 0; i < 4; i++) {
+ godot_string s;
+ godot_string_new_with_latin1_chars(&s, nums[i]);
+ CHECK(!(ABS(godot_string_to_float(&s) - num[i]) > 0.00001));
+ godot_string_destroy(&s);
+
+ CHECK(!(ABS(godot_string_char_to_float(nums[i]) - num[i]) > 0.00001));
+ CHECK(!(ABS(godot_string_wchar_to_float(wnums[i], nullptr) - num[i]) > 0.00001));
+ }
+}
+
+TEST_CASE("[GDNatvie String] CamelCase to underscore") {
+ godot_string s, t;
+ godot_string_new_with_latin1_chars(&s, "TestTestStringGD");
+
+ t = godot_string_camelcase_to_underscore(&s);
+ CHECK(u32scmp(godot_string_get_data(&t), U"Test_Test_String_GD") == 0);
+ godot_string_destroy(&t);
+
+ t = godot_string_camelcase_to_underscore_lowercased(&s);
+ CHECK(u32scmp(godot_string_get_data(&t), U"test_test_string_gd") == 0);
+ godot_string_destroy(&t);
+
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Slicing") {
+ godot_string s, c;
+ godot_string_new_with_latin1_chars(&s, "Mars,Jupiter,Saturn,Uranus");
+ godot_string_new_with_latin1_chars(&c, ",");
+
+ const char32_t *slices[4] = { U"Mars", U"Jupiter", U"Saturn", U"Uranus" };
+ for (int i = 0; i < godot_string_get_slice_count(&s, &c); i++) {
+ godot_string t;
+ t = godot_string_get_slice(&s, &c, i);
+ CHECK(u32scmp(godot_string_get_data(&t), slices[i]) == 0);
+ godot_string_destroy(&t);
+
+ t = godot_string_get_slicec(&s, U',', i);
+ CHECK(u32scmp(godot_string_get_data(&t), slices[i]) == 0);
+ godot_string_destroy(&t);
+ }
+
+ godot_string_destroy(&c);
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Splitting") {
+ godot_string s, c;
+ godot_string_new_with_latin1_chars(&s, "Mars,Jupiter,Saturn,Uranus");
+ godot_string_new_with_latin1_chars(&c, ",");
+
+ godot_packed_string_array l;
+
+ const char32_t *slices_l[3] = { U"Mars", U"Jupiter", U"Saturn,Uranus" };
+ const char32_t *slices_r[3] = { U"Mars,Jupiter", U"Saturn", U"Uranus" };
+
+ l = godot_string_split_with_maxsplit(&s, &c, true, 2);
+ CHECK(godot_packed_string_array_size(&l) == 3);
+ for (int i = 0; i < godot_packed_string_array_size(&l); i++) {
+ godot_string t = godot_packed_string_array_get(&l, i);
+ CHECK(u32scmp(godot_string_get_data(&t), slices_l[i]) == 0);
+ godot_string_destroy(&t);
+ }
+ godot_packed_string_array_destroy(&l);
+
+ l = godot_string_rsplit_with_maxsplit(&s, &c, true, 2);
+ CHECK(godot_packed_string_array_size(&l) == 3);
+ for (int i = 0; i < godot_packed_string_array_size(&l); i++) {
+ godot_string t = godot_packed_string_array_get(&l, i);
+ CHECK(u32scmp(godot_string_get_data(&t), slices_r[i]) == 0);
+ godot_string_destroy(&t);
+ }
+ godot_packed_string_array_destroy(&l);
+ godot_string_destroy(&s);
+
+ godot_string_new_with_latin1_chars(&s, "Mars Jupiter Saturn Uranus");
+ const char32_t *slices_s[4] = { U"Mars", U"Jupiter", U"Saturn", U"Uranus" };
+ l = godot_string_split_spaces(&s);
+ for (int i = 0; i < godot_packed_string_array_size(&l); i++) {
+ godot_string t = godot_packed_string_array_get(&l, i);
+ CHECK(u32scmp(godot_string_get_data(&t), slices_s[i]) == 0);
+ godot_string_destroy(&t);
+ }
+ godot_packed_string_array_destroy(&l);
+ godot_string_destroy(&s);
+
+ godot_string c1, c2;
+ godot_string_new_with_latin1_chars(&c1, ";");
+ godot_string_new_with_latin1_chars(&c2, " ");
+
+ godot_string_new_with_latin1_chars(&s, "1.2;2.3 4.5");
+ const double slices_d[3] = { 1.2, 2.3, 4.5 };
+
+ godot_packed_float32_array lf = godot_string_split_floats_allow_empty(&s, &c1);
+ CHECK(godot_packed_float32_array_size(&lf) == 2);
+ for (int i = 0; i < godot_packed_float32_array_size(&lf); i++) {
+ CHECK(ABS(godot_packed_float32_array_get(&lf, i) - slices_d[i]) <= 0.00001);
+ }
+ godot_packed_float32_array_destroy(&lf);
+
+ godot_packed_string_array keys;
+ godot_packed_string_array_new(&keys);
+ godot_packed_string_array_push_back(&keys, &c1);
+ godot_packed_string_array_push_back(&keys, &c2);
+
+ lf = godot_string_split_floats_mk_allow_empty(&s, &keys);
+ CHECK(godot_packed_float32_array_size(&lf) == 3);
+ for (int i = 0; i < godot_packed_float32_array_size(&lf); i++) {
+ CHECK(ABS(godot_packed_float32_array_get(&lf, i) - slices_d[i]) <= 0.00001);
+ }
+ godot_packed_float32_array_destroy(&lf);
+
+ godot_string_destroy(&s);
+ godot_string_new_with_latin1_chars(&s, "1;2 4");
+ const int slices_i[3] = { 1, 2, 4 };
+
+ godot_packed_int32_array li = godot_string_split_ints_allow_empty(&s, &c1);
+ CHECK(godot_packed_int32_array_size(&li) == 2);
+ for (int i = 0; i < godot_packed_int32_array_size(&li); i++) {
+ CHECK(godot_packed_int32_array_get(&li, i) == slices_i[i]);
+ }
+ godot_packed_int32_array_destroy(&li);
+
+ li = godot_string_split_ints_mk_allow_empty(&s, &keys);
+ CHECK(godot_packed_int32_array_size(&li) == 3);
+ for (int i = 0; i < godot_packed_int32_array_size(&li); i++) {
+ CHECK(godot_packed_int32_array_get(&li, i) == slices_i[i]);
+ }
+ godot_packed_int32_array_destroy(&li);
+
+ godot_string_destroy(&s);
+ godot_string_destroy(&c);
+ godot_string_destroy(&c1);
+ godot_string_destroy(&c2);
+ godot_packed_string_array_destroy(&keys);
+}
+
+TEST_CASE("[GDNatvie String] Erasing") {
+ godot_string s, t;
+ godot_string_new_with_latin1_chars(&s, "Josephine is such a cute girl!");
+ godot_string_new_with_latin1_chars(&t, "cute ");
+
+ godot_string_erase(&s, godot_string_find(&s, &t), godot_string_length(&t));
+
+ CHECK(u32scmp(godot_string_get_data(&s), U"Josephine is such a girl!") == 0);
+
+ godot_string_destroy(&s);
+ godot_string_destroy(&t);
+}
+
+struct test_27_data {
+ char const *data;
+ char const *part;
+ bool expected;
+};
+
+TEST_CASE("[GDNatvie String] Begins with") {
+ test_27_data tc[] = {
+ { "res://foobar", "res://", true },
+ { "res", "res://", false },
+ { "abc", "abc", true }
+ };
+ size_t count = sizeof(tc) / sizeof(tc[0]);
+ bool state = true;
+ for (size_t i = 0; state && i < count; ++i) {
+ godot_string s;
+ godot_string_new_with_latin1_chars(&s, tc[i].data);
+
+ state = godot_string_begins_with_char_array(&s, tc[i].part) == tc[i].expected;
+ if (state) {
+ godot_string t;
+ godot_string_new_with_latin1_chars(&t, tc[i].part);
+ state = godot_string_begins_with(&s, &t) == tc[i].expected;
+ godot_string_destroy(&t);
+ }
+ godot_string_destroy(&s);
+
+ CHECK(state);
+ if (!state) {
+ break;
+ }
+ };
+ CHECK(state);
+}
+
+TEST_CASE("[GDNatvie String] Ends with") {
+ test_27_data tc[] = {
+ { "res://foobar", "foobar", true },
+ { "res", "res://", false },
+ { "abc", "abc", true }
+ };
+ size_t count = sizeof(tc) / sizeof(tc[0]);
+ bool state = true;
+ for (size_t i = 0; state && i < count; ++i) {
+ godot_string s;
+ godot_string_new_with_latin1_chars(&s, tc[i].data);
+
+ state = godot_string_ends_with_char_array(&s, tc[i].part) == tc[i].expected;
+ if (state) {
+ godot_string t;
+ godot_string_new_with_latin1_chars(&t, tc[i].part);
+ state = godot_string_ends_with(&s, &t) == tc[i].expected;
+ godot_string_destroy(&t);
+ }
+ godot_string_destroy(&s);
+
+ CHECK(state);
+ if (!state) {
+ break;
+ }
+ };
+ CHECK(state);
+}
+
+TEST_CASE("[GDNatvie String] format") {
+ godot_string value_format, t;
+ godot_string_new_with_latin1_chars(&value_format, "red=\"$red\" green=\"$green\" blue=\"$blue\" alpha=\"$alpha\"");
+
+ godot_variant key_v, val_v;
+ godot_dictionary value_dictionary;
+ godot_dictionary_new(&value_dictionary);
+
+ godot_string_new_with_latin1_chars(&t, "red");
+ godot_variant_new_string(&key_v, &t);
+ godot_string_destroy(&t);
+ godot_variant_new_int(&val_v, 10);
+ godot_dictionary_set(&value_dictionary, &key_v, &val_v);
+ godot_variant_destroy(&key_v);
+ godot_variant_destroy(&val_v);
+
+ godot_string_new_with_latin1_chars(&t, "green");
+ godot_variant_new_string(&key_v, &t);
+ godot_string_destroy(&t);
+ godot_variant_new_int(&val_v, 20);
+ godot_dictionary_set(&value_dictionary, &key_v, &val_v);
+ godot_variant_destroy(&key_v);
+ godot_variant_destroy(&val_v);
+
+ godot_string_new_with_latin1_chars(&t, "blue");
+ godot_variant_new_string(&key_v, &t);
+ godot_string_destroy(&t);
+ godot_string_new_with_latin1_chars(&t, "bla");
+ godot_variant_new_string(&val_v, &t);
+ godot_string_destroy(&t);
+ godot_dictionary_set(&value_dictionary, &key_v, &val_v);
+ godot_variant_destroy(&key_v);
+ godot_variant_destroy(&val_v);
+
+ godot_string_new_with_latin1_chars(&t, "alpha");
+ godot_variant_new_string(&key_v, &t);
+ godot_string_destroy(&t);
+ godot_variant_new_real(&val_v, 0.4);
+ godot_dictionary_set(&value_dictionary, &key_v, &val_v);
+ godot_variant_destroy(&key_v);
+ godot_variant_destroy(&val_v);
+
+ godot_variant dict_v;
+ godot_variant_new_dictionary(&dict_v, &value_dictionary);
+ godot_string s = godot_string_format_with_custom_placeholder(&value_format, &dict_v, "$_");
+
+ CHECK(u32scmp(godot_string_get_data(&s), U"red=\"10\" green=\"20\" blue=\"bla\" alpha=\"0.4\"") == 0);
+
+ godot_dictionary_destroy(&value_dictionary);
+ godot_string_destroy(&s);
+ godot_variant_destroy(&dict_v);
+ godot_string_destroy(&value_format);
+}
+
+TEST_CASE("[GDNatvie String] sprintf") {
+ //godot_string GDAPI (const godot_string *p_self, const godot_array *p_values, godot_bool *p_error);
+ godot_string format, output;
+ godot_array args;
+ bool error;
+
+#define ARRAY_PUSH_STRING(x) \
+ { \
+ godot_variant v; \
+ godot_string t; \
+ godot_string_new_with_latin1_chars(&t, x); \
+ godot_variant_new_string(&v, &t); \
+ godot_string_destroy(&t); \
+ godot_array_push_back(&args, &v); \
+ godot_variant_destroy(&v); \
+ }
+
+#define ARRAY_PUSH_INT(x) \
+ { \
+ godot_variant v; \
+ godot_variant_new_int(&v, x); \
+ godot_array_push_back(&args, &v); \
+ godot_variant_destroy(&v); \
+ }
+
+#define ARRAY_PUSH_REAL(x) \
+ { \
+ godot_variant v; \
+ godot_variant_new_real(&v, x); \
+ godot_array_push_back(&args, &v); \
+ godot_variant_destroy(&v); \
+ }
+
+ godot_array_new(&args);
+
+ // %%
+ godot_string_new_with_latin1_chars(&format, "fish %% frog");
+ godot_array_clear(&args);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish % frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+ //////// INTS
+
+ // Int
+ godot_string_new_with_latin1_chars(&format, "fish %d frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_INT(5);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish 5 frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Int left padded with zeroes.
+ godot_string_new_with_latin1_chars(&format, "fish %05d frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_INT(5);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish 00005 frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Int left padded with spaces.
+ godot_string_new_with_latin1_chars(&format, "fish %5d frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_INT(5);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish 5 frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Int right padded with spaces.
+ godot_string_new_with_latin1_chars(&format, "fish %-5d frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_INT(5);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish 5 frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Int with sign (positive).
+ godot_string_new_with_latin1_chars(&format, "fish %+d frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_INT(5);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish +5 frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Negative int.
+ godot_string_new_with_latin1_chars(&format, "fish %d frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_INT(-5);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish -5 frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Hex (lower)
+ godot_string_new_with_latin1_chars(&format, "fish %x frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_INT(45);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish 2d frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Hex (upper)
+ godot_string_new_with_latin1_chars(&format, "fish %X frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_INT(45);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish 2D frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Octal
+ godot_string_new_with_latin1_chars(&format, "fish %o frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_INT(99);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish 143 frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+ ////// REALS
+
+ // Real
+ godot_string_new_with_latin1_chars(&format, "fish %f frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_REAL(99.99);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish 99.990000 frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Real left-padded
+ godot_string_new_with_latin1_chars(&format, "fish %11f frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_REAL(99.99);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish 99.990000 frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Real right-padded
+ godot_string_new_with_latin1_chars(&format, "fish %-11f frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_REAL(99.99);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish 99.990000 frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Real given int.
+ godot_string_new_with_latin1_chars(&format, "fish %f frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_REAL(99);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish 99.000000 frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Real with sign (positive).
+ godot_string_new_with_latin1_chars(&format, "fish %+f frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_REAL(99.99);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish +99.990000 frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Real with 1 decimals.
+ godot_string_new_with_latin1_chars(&format, "fish %.1f frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_REAL(99.99);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish 100.0 frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Real with 12 decimals.
+ godot_string_new_with_latin1_chars(&format, "fish %.12f frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_REAL(99.99);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish 99.990000000000 frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Real with no decimals.
+ godot_string_new_with_latin1_chars(&format, "fish %.f frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_REAL(99.99);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish 100 frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ /////// Strings.
+
+ // String
+ godot_string_new_with_latin1_chars(&format, "fish %s frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_STRING("cheese");
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish cheese frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // String left-padded
+ godot_string_new_with_latin1_chars(&format, "fish %10s frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_STRING("cheese");
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish cheese frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // String right-padded
+ godot_string_new_with_latin1_chars(&format, "fish %-10s frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_STRING("cheese");
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish cheese frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ ///// Characters
+
+ // Character as string.
+ godot_string_new_with_latin1_chars(&format, "fish %c frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_STRING("A");
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish A frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Character as int.
+ godot_string_new_with_latin1_chars(&format, "fish %c frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_INT(65);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish A frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ ///// Dynamic width
+
+ // String dynamic width
+ godot_string_new_with_latin1_chars(&format, "fish %*s frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_INT(10);
+ ARRAY_PUSH_STRING("cheese");
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ REQUIRE(u32scmp(godot_string_get_data(&output), U"fish cheese frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Int dynamic width
+ godot_string_new_with_latin1_chars(&format, "fish %*d frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_INT(10);
+ ARRAY_PUSH_INT(99);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ REQUIRE(u32scmp(godot_string_get_data(&output), U"fish 99 frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Float dynamic width
+ godot_string_new_with_latin1_chars(&format, "fish %*.*f frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_INT(10);
+ ARRAY_PUSH_INT(3);
+ ARRAY_PUSH_REAL(99.99);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error == false);
+ CHECK(u32scmp(godot_string_get_data(&output), U"fish 99.990 frog") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ ///// Errors
+
+ // More formats than arguments.
+ godot_string_new_with_latin1_chars(&format, "fish %s %s frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_STRING("cheese");
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error);
+ CHECK(u32scmp(godot_string_get_data(&output), U"not enough arguments for format string") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // More arguments than formats.
+ godot_string_new_with_latin1_chars(&format, "fish %s frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_STRING("hello");
+ ARRAY_PUSH_STRING("cheese");
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error);
+ CHECK(u32scmp(godot_string_get_data(&output), U"not all arguments converted during string formatting") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Incomplete format.
+ godot_string_new_with_latin1_chars(&format, "fish %10");
+ godot_array_clear(&args);
+ ARRAY_PUSH_STRING("cheese");
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error);
+ CHECK(u32scmp(godot_string_get_data(&output), U"incomplete format") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Bad character in format string
+ godot_string_new_with_latin1_chars(&format, "fish %&f frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_STRING("cheese");
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error);
+ CHECK(u32scmp(godot_string_get_data(&output), U"unsupported format character") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Too many decimals.
+ godot_string_new_with_latin1_chars(&format, "fish %2.2.2f frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_REAL(99.99);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error);
+ CHECK(u32scmp(godot_string_get_data(&output), U"too many decimal points in format") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // * not a number
+ godot_string_new_with_latin1_chars(&format, "fish %*f frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_STRING("cheese");
+ ARRAY_PUSH_REAL(99.99);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error);
+ CHECK(u32scmp(godot_string_get_data(&output), U"* wants number") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Character too long.
+ godot_string_new_with_latin1_chars(&format, "fish %c frog");
+ godot_array_clear(&args);
+ ARRAY_PUSH_STRING("sc");
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error);
+ CHECK(u32scmp(godot_string_get_data(&output), U"%c requires number or single-character string") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ // Character bad type.
+ godot_string_new_with_latin1_chars(&format, "fish %c frog");
+ godot_array_clear(&args);
+ godot_array t;
+ godot_array_new(&t);
+ godot_variant v;
+ godot_variant_new_array(&v, &t);
+ godot_array_destroy(&t);
+ godot_array_push_back(&args, &v);
+ godot_variant_destroy(&v);
+ output = godot_string_sprintf(&format, &args, &error);
+ REQUIRE(error);
+ CHECK(u32scmp(godot_string_get_data(&output), U"%c requires number or single-character string") == 0);
+ godot_string_destroy(&format);
+ godot_string_destroy(&output);
+
+ godot_array_destroy(&args);
+#undef ARRAY_PUSH_INT
+#undef ARRAY_PUSH_REAL
+#undef ARRAY_PUSH_STRING
+}
+
+TEST_CASE("[GDNatvie String] is_numeric") {
+#define IS_NUM_TEST(x, r) \
+ { \
+ godot_string t; \
+ godot_string_new_with_latin1_chars(&t, x); \
+ CHECK(godot_string_is_numeric(&t) == r); \
+ godot_string_destroy(&t); \
+ }
+
+ IS_NUM_TEST("12", true);
+ IS_NUM_TEST("1.2", true);
+ IS_NUM_TEST("AF", false);
+ IS_NUM_TEST("-12", true);
+ IS_NUM_TEST("-1.2", true);
+
+#undef IS_NUM_TEST
+}
+
+TEST_CASE("[GDNatvie String] pad") {
+ godot_string s, c;
+ godot_string_new_with_latin1_chars(&s, "test");
+ godot_string_new_with_latin1_chars(&c, "x");
+
+ godot_string l = godot_string_lpad_with_custom_character(&s, 10, &c);
+ CHECK(u32scmp(godot_string_get_data(&l), U"xxxxxxtest") == 0);
+ godot_string_destroy(&l);
+
+ godot_string r = godot_string_rpad_with_custom_character(&s, 10, &c);
+ CHECK(u32scmp(godot_string_get_data(&r), U"testxxxxxx") == 0);
+ godot_string_destroy(&r);
+
+ godot_string_destroy(&s);
+ godot_string_destroy(&c);
+
+ godot_string_new_with_latin1_chars(&s, "10.10");
+ c = godot_string_pad_decimals(&s, 4);
+ CHECK(u32scmp(godot_string_get_data(&c), U"10.1000") == 0);
+ godot_string_destroy(&c);
+ c = godot_string_pad_zeros(&s, 4);
+ CHECK(u32scmp(godot_string_get_data(&c), U"0010.10") == 0);
+ godot_string_destroy(&c);
+
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] is_subsequence_of") {
+ godot_string a, t;
+ godot_string_new_with_latin1_chars(&a, "is subsequence of");
+
+ godot_string_new_with_latin1_chars(&t, "sub");
+ CHECK(godot_string_is_subsequence_of(&t, &a));
+ godot_string_destroy(&t);
+
+ godot_string_new_with_latin1_chars(&t, "Sub");
+ CHECK(!godot_string_is_subsequence_of(&t, &a));
+ godot_string_destroy(&t);
+
+ godot_string_new_with_latin1_chars(&t, "Sub");
+ CHECK(godot_string_is_subsequence_ofi(&t, &a));
+ godot_string_destroy(&t);
+
+ godot_string_destroy(&a);
+}
+
+TEST_CASE("[GDNatvie String] match") {
+ godot_string s, t;
+ godot_string_new_with_latin1_chars(&s, "*.png");
+
+ godot_string_new_with_latin1_chars(&t, "img1.png");
+ CHECK(godot_string_match(&t, &s));
+ godot_string_destroy(&t);
+
+ godot_string_new_with_latin1_chars(&t, "img1.jpeg");
+ CHECK(!godot_string_match(&t, &s));
+ godot_string_destroy(&t);
+
+ godot_string_new_with_latin1_chars(&t, "img1.Png");
+ CHECK(!godot_string_match(&t, &s));
+ CHECK(godot_string_matchn(&t, &s));
+ godot_string_destroy(&t);
+
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] IPVX address to string") {
+ godot_string ip;
+
+ godot_string_new_with_latin1_chars(&ip, "192.168.0.1");
+ CHECK(godot_string_is_valid_ip_address(&ip));
+ godot_string_destroy(&ip);
+
+ godot_string_new_with_latin1_chars(&ip, "192.368.0.1");
+ CHECK(!godot_string_is_valid_ip_address(&ip));
+ godot_string_destroy(&ip);
+
+ godot_string_new_with_latin1_chars(&ip, "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
+ CHECK(godot_string_is_valid_ip_address(&ip));
+ godot_string_destroy(&ip);
+
+ godot_string_new_with_latin1_chars(&ip, "2001:0db8:85j3:0000:0000:8a2e:0370:7334");
+ CHECK(!godot_string_is_valid_ip_address(&ip));
+ godot_string_destroy(&ip);
+
+ godot_string_new_with_latin1_chars(&ip, "2001:0db8:85f345:0000:0000:8a2e:0370:7334");
+ CHECK(!godot_string_is_valid_ip_address(&ip));
+ godot_string_destroy(&ip);
+
+ godot_string_new_with_latin1_chars(&ip, "2001:0db8::0:8a2e:370:7334");
+ CHECK(godot_string_is_valid_ip_address(&ip));
+ godot_string_destroy(&ip);
+
+ godot_string_new_with_latin1_chars(&ip, "::ffff:192.168.0.1");
+ CHECK(godot_string_is_valid_ip_address(&ip));
+ godot_string_destroy(&ip);
+}
+
+TEST_CASE("[GDNatvie String] Capitalize against many strings") {
+#define CAP_TEST(i, o) \
+ godot_string_new_with_latin1_chars(&input, i); \
+ godot_string_new_with_latin1_chars(&output, o); \
+ test = godot_string_capitalize(&input); \
+ CHECK(u32scmp(godot_string_get_data(&output), godot_string_get_data(&test)) == 0); \
+ godot_string_destroy(&input); \
+ godot_string_destroy(&output); \
+ godot_string_destroy(&test);
+
+ godot_string input, output, test;
+
+ CAP_TEST("bytes2var", "Bytes 2 Var");
+ CAP_TEST("linear2db", "Linear 2 Db");
+ CAP_TEST("vector3", "Vector 3");
+ CAP_TEST("sha256", "Sha 256");
+ CAP_TEST("2db", "2 Db");
+ CAP_TEST("PascalCase", "Pascal Case");
+ CAP_TEST("PascalPascalCase", "Pascal Pascal Case");
+ CAP_TEST("snake_case", "Snake Case");
+ CAP_TEST("snake_snake_case", "Snake Snake Case");
+ CAP_TEST("sha256sum", "Sha 256 Sum");
+ CAP_TEST("cat2dog", "Cat 2 Dog");
+ CAP_TEST("function(name)", "Function(name)");
+ CAP_TEST("snake_case_function(snake_case_arg)", "Snake Case Function(snake Case Arg)");
+ CAP_TEST("snake_case_function( snake_case_arg )", "Snake Case Function( Snake Case Arg )");
+
+#undef CAP_TEST
+}
+
+TEST_CASE("[GDNatvie String] lstrip and rstrip") {
+#define LSTRIP_TEST(x, y, z) \
+ { \
+ godot_string xx, yy, zz, rr; \
+ godot_string_new_with_latin1_chars(&xx, x); \
+ godot_string_new_with_latin1_chars(&yy, y); \
+ godot_string_new_with_latin1_chars(&zz, z); \
+ rr = godot_string_lstrip(&xx, &yy); \
+ state = state && (u32scmp(godot_string_get_data(&rr), godot_string_get_data(&zz)) == 0); \
+ godot_string_destroy(&xx); \
+ godot_string_destroy(&yy); \
+ godot_string_destroy(&zz); \
+ godot_string_destroy(&rr); \
+ }
+
+#define RSTRIP_TEST(x, y, z) \
+ { \
+ godot_string xx, yy, zz, rr; \
+ godot_string_new_with_latin1_chars(&xx, x); \
+ godot_string_new_with_latin1_chars(&yy, y); \
+ godot_string_new_with_latin1_chars(&zz, z); \
+ rr = godot_string_rstrip(&xx, &yy); \
+ state = state && (u32scmp(godot_string_get_data(&rr), godot_string_get_data(&zz)) == 0); \
+ godot_string_destroy(&xx); \
+ godot_string_destroy(&yy); \
+ godot_string_destroy(&zz); \
+ godot_string_destroy(&rr); \
+ }
+
+#define LSTRIP_UTF8_TEST(x, y, z) \
+ { \
+ godot_string xx, yy, zz, rr; \
+ godot_string_new_with_utf8_chars(&xx, x); \
+ godot_string_new_with_utf8_chars(&yy, y); \
+ godot_string_new_with_utf8_chars(&zz, z); \
+ rr = godot_string_lstrip(&xx, &yy); \
+ state = state && (u32scmp(godot_string_get_data(&rr), godot_string_get_data(&zz)) == 0); \
+ godot_string_destroy(&xx); \
+ godot_string_destroy(&yy); \
+ godot_string_destroy(&zz); \
+ godot_string_destroy(&rr); \
+ }
+
+#define RSTRIP_UTF8_TEST(x, y, z) \
+ { \
+ godot_string xx, yy, zz, rr; \
+ godot_string_new_with_utf8_chars(&xx, x); \
+ godot_string_new_with_utf8_chars(&yy, y); \
+ godot_string_new_with_utf8_chars(&zz, z); \
+ rr = godot_string_rstrip(&xx, &yy); \
+ state = state && (u32scmp(godot_string_get_data(&rr), godot_string_get_data(&zz)) == 0); \
+ godot_string_destroy(&xx); \
+ godot_string_destroy(&yy); \
+ godot_string_destroy(&zz); \
+ godot_string_destroy(&rr); \
+ }
+
+ bool state = true;
+
+ // strip none
+ LSTRIP_TEST("abc", "", "abc");
+ RSTRIP_TEST("abc", "", "abc");
+ // strip one
+ LSTRIP_TEST("abc", "a", "bc");
+ RSTRIP_TEST("abc", "c", "ab");
+ // strip lots
+ LSTRIP_TEST("bababbababccc", "ab", "ccc");
+ RSTRIP_TEST("aaabcbcbcbbcbbc", "cb", "aaa");
+ // strip empty string
+ LSTRIP_TEST("", "", "");
+ RSTRIP_TEST("", "", "");
+ // strip to empty string
+ LSTRIP_TEST("abcabcabc", "bca", "");
+ RSTRIP_TEST("abcabcabc", "bca", "");
+ // don't strip wrong end
+ LSTRIP_TEST("abc", "c", "abc");
+ LSTRIP_TEST("abca", "a", "bca");
+ RSTRIP_TEST("abc", "a", "abc");
+ RSTRIP_TEST("abca", "a", "abc");
+ // in utf-8 "¿" (\u00bf) has the same first byte as "µ" (\u00b5)
+ // and the same second as "ÿ" (\u00ff)
+ LSTRIP_UTF8_TEST("¿", "µÿ", "¿");
+ RSTRIP_UTF8_TEST("¿", "µÿ", "¿");
+ LSTRIP_UTF8_TEST("µ¿ÿ", "µÿ", "¿ÿ");
+ RSTRIP_UTF8_TEST("µ¿ÿ", "µÿ", "µ¿");
+
+ // the above tests repeated with additional superfluous strip chars
+
+ // strip none
+ LSTRIP_TEST("abc", "qwjkl", "abc");
+ RSTRIP_TEST("abc", "qwjkl", "abc");
+ // strip one
+ LSTRIP_TEST("abc", "qwajkl", "bc");
+ RSTRIP_TEST("abc", "qwcjkl", "ab");
+ // strip lots
+ LSTRIP_TEST("bababbababccc", "qwabjkl", "ccc");
+ RSTRIP_TEST("aaabcbcbcbbcbbc", "qwcbjkl", "aaa");
+ // strip empty string
+ LSTRIP_TEST("", "qwjkl", "");
+ RSTRIP_TEST("", "qwjkl", "");
+ // strip to empty string
+ LSTRIP_TEST("abcabcabc", "qwbcajkl", "");
+ RSTRIP_TEST("abcabcabc", "qwbcajkl", "");
+ // don't strip wrong end
+ LSTRIP_TEST("abc", "qwcjkl", "abc");
+ LSTRIP_TEST("abca", "qwajkl", "bca");
+ RSTRIP_TEST("abc", "qwajkl", "abc");
+ RSTRIP_TEST("abca", "qwajkl", "abc");
+ // in utf-8 "¿" (\u00bf) has the same first byte as "µ" (\u00b5)
+ // and the same second as "ÿ" (\u00ff)
+ LSTRIP_UTF8_TEST("¿", "qwaµÿjkl", "¿");
+ RSTRIP_UTF8_TEST("¿", "qwaµÿjkl", "¿");
+ LSTRIP_UTF8_TEST("µ¿ÿ", "qwaµÿjkl", "¿ÿ");
+ RSTRIP_UTF8_TEST("µ¿ÿ", "qwaµÿjkl", "µ¿");
+
+ CHECK(state);
+
+#undef LSTRIP_TEST
+#undef RSTRIP_TEST
+#undef LSTRIP_UTF8_TEST
+#undef RSTRIP_UTF8_TEST
+}
+
+TEST_CASE("[GDNatvie String] Cyrillic to_lower()") {
+ godot_string upper, lower, test;
+ godot_string_new_with_utf8_chars(&upper, "ÐБВГДЕÐЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯ");
+ godot_string_new_with_utf8_chars(&lower, "абвгдеёжзийклмнопрÑтуфхцчшщъыьÑÑŽÑ");
+
+ test = godot_string_to_lower(&upper);
+
+ CHECK((u32scmp(godot_string_get_data(&test), godot_string_get_data(&lower)) == 0));
+
+ godot_string_destroy(&upper);
+ godot_string_destroy(&lower);
+ godot_string_destroy(&test);
+}
+
+TEST_CASE("[GDNatvie String] Count and countn functionality") {
+#define COUNT_TEST(x, y, r) \
+ { \
+ godot_string s, t; \
+ godot_string_new_with_latin1_chars(&s, x); \
+ godot_string_new_with_latin1_chars(&t, y); \
+ state = state && (godot_string_count(&s, &t, 0, 0) == r); \
+ godot_string_destroy(&s); \
+ godot_string_destroy(&t); \
+ }
+
+#define COUNTR_TEST(x, y, a, b, r) \
+ { \
+ godot_string s, t; \
+ godot_string_new_with_latin1_chars(&s, x); \
+ godot_string_new_with_latin1_chars(&t, y); \
+ state = state && (godot_string_count(&s, &t, a, b) == r); \
+ godot_string_destroy(&s); \
+ godot_string_destroy(&t); \
+ }
+
+#define COUNTN_TEST(x, y, r) \
+ { \
+ godot_string s, t; \
+ godot_string_new_with_latin1_chars(&s, x); \
+ godot_string_new_with_latin1_chars(&t, y); \
+ state = state && (godot_string_countn(&s, &t, 0, 0) == r); \
+ godot_string_destroy(&s); \
+ godot_string_destroy(&t); \
+ }
+
+#define COUNTNR_TEST(x, y, a, b, r) \
+ { \
+ godot_string s, t; \
+ godot_string_new_with_latin1_chars(&s, x); \
+ godot_string_new_with_latin1_chars(&t, y); \
+ state = state && (godot_string_countn(&s, &t, a, b) == r); \
+ godot_string_destroy(&s); \
+ godot_string_destroy(&t); \
+ }
+ bool state = true;
+
+ COUNT_TEST("", "Test", 0);
+ COUNT_TEST("Test", "", 0);
+ COUNT_TEST("Test", "test", 0);
+ COUNT_TEST("Test", "TEST", 0);
+ COUNT_TEST("TEST", "TEST", 1);
+ COUNT_TEST("Test", "Test", 1);
+ COUNT_TEST("aTest", "Test", 1);
+ COUNT_TEST("Testa", "Test", 1);
+ COUNT_TEST("TestTestTest", "Test", 3);
+ COUNT_TEST("TestTestTest", "TestTest", 1);
+ COUNT_TEST("TestGodotTestGodotTestGodot", "Test", 3);
+
+ COUNTR_TEST("TestTestTestTest", "Test", 4, 8, 1);
+ COUNTR_TEST("TestTestTestTest", "Test", 4, 12, 2);
+ COUNTR_TEST("TestTestTestTest", "Test", 4, 16, 3);
+ COUNTR_TEST("TestTestTestTest", "Test", 4, 0, 3);
+
+ COUNTN_TEST("Test", "test", 1);
+ COUNTN_TEST("Test", "TEST", 1);
+ COUNTN_TEST("testTest-Testatest", "tEst", 4);
+ COUNTNR_TEST("testTest-TeStatest", "tEsT", 4, 16, 2);
+
+ CHECK(state);
+
+#undef COUNT_TEST
+#undef COUNTR_TEST
+#undef COUNTN_TEST
+#undef COUNTNR_TEST
+}
+
+TEST_CASE("[GDNatvie String] Bigrams") {
+ godot_string s, t;
+ godot_string_new_with_latin1_chars(&s, "abcd");
+ godot_packed_string_array bigr = godot_string_bigrams(&s);
+ godot_string_destroy(&s);
+
+ CHECK(godot_packed_string_array_size(&bigr) == 3);
+
+ t = godot_packed_string_array_get(&bigr, 0);
+ CHECK(u32scmp(godot_string_get_data(&t), U"ab") == 0);
+ godot_string_destroy(&t);
+
+ t = godot_packed_string_array_get(&bigr, 1);
+ CHECK(u32scmp(godot_string_get_data(&t), U"bc") == 0);
+ godot_string_destroy(&t);
+
+ t = godot_packed_string_array_get(&bigr, 2);
+ CHECK(u32scmp(godot_string_get_data(&t), U"cd") == 0);
+ godot_string_destroy(&t);
+
+ godot_packed_string_array_destroy(&bigr);
+}
+
+TEST_CASE("[GDNatvie String] c-escape/unescape") {
+ godot_string s;
+ godot_string_new_with_latin1_chars(&s, "\\1\a2\b\f3\n45\r6\t7\v8\'9\?0\"");
+ godot_string t = godot_string_c_escape(&s);
+ godot_string u = godot_string_c_unescape(&t);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&s)) == 0);
+ godot_string_destroy(&u);
+ godot_string_destroy(&t);
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] dedent") {
+ godot_string s, t;
+ godot_string_new_with_latin1_chars(&s, " aaa\n bbb");
+ godot_string_new_with_latin1_chars(&t, "aaa\nbbb");
+ godot_string u = godot_string_dedent(&s);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
+ godot_string_destroy(&u);
+ godot_string_destroy(&t);
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Path functions") {
+ static const char *path[4] = { "C:\\Godot\\project\\test.tscn", "/Godot/project/test.xscn", "../Godot/project/test.scn", "Godot\\test.doc" };
+ static const char *base_dir[4] = { "C:\\Godot\\project", "/Godot/project", "../Godot/project", "Godot" };
+ static const char *base_name[4] = { "C:\\Godot\\project\\test", "/Godot/project/test", "../Godot/project/test", "Godot\\test" };
+ static const char *ext[4] = { "tscn", "xscn", "scn", "doc" };
+ static const char *file[4] = { "test.tscn", "test.xscn", "test.scn", "test.doc" };
+ static const bool abs[4] = { true, true, false, false };
+
+ for (int i = 0; i < 4; i++) {
+ godot_string s, t, u, f;
+ godot_string_new_with_latin1_chars(&s, path[i]);
+
+ t = godot_string_get_base_dir(&s);
+ godot_string_new_with_latin1_chars(&u, base_dir[i]);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
+ godot_string_destroy(&u);
+ godot_string_destroy(&t);
+
+ t = godot_string_get_basename(&s);
+ godot_string_new_with_latin1_chars(&u, base_name[i]);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
+ godot_string_destroy(&u);
+ godot_string_destroy(&t);
+
+ t = godot_string_get_extension(&s);
+ godot_string_new_with_latin1_chars(&u, ext[i]);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
+ godot_string_destroy(&u);
+ godot_string_destroy(&t);
+
+ t = godot_string_get_file(&s);
+ godot_string_new_with_latin1_chars(&u, file[i]);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
+ godot_string_destroy(&u);
+ godot_string_destroy(&t);
+
+ godot_string s_simp;
+ s_simp = godot_string_simplify_path(&s);
+ t = godot_string_get_base_dir(&s_simp);
+ godot_string_new_with_latin1_chars(&u, file[i]);
+ f = godot_string_plus_file(&t, &u);
+ CHECK(u32scmp(godot_string_get_data(&f), godot_string_get_data(&s_simp)) == 0);
+ godot_string_destroy(&f);
+ godot_string_destroy(&u);
+ godot_string_destroy(&t);
+ godot_string_destroy(&s_simp);
+
+ CHECK(godot_string_is_abs_path(&s) == abs[i]);
+ CHECK(godot_string_is_rel_path(&s) != abs[i]);
+
+ godot_string_destroy(&s);
+ }
+
+ static const char *file_name[3] = { "test.tscn", "test://.xscn", "?tes*t.scn" };
+ static const bool valid[3] = { true, false, false };
+ for (int i = 0; i < 3; i++) {
+ godot_string s;
+ godot_string_new_with_latin1_chars(&s, file_name[i]);
+ CHECK(godot_string_is_valid_filename(&s) == valid[i]);
+ godot_string_destroy(&s);
+ }
+}
+
+TEST_CASE("[GDNatvie String] hash") {
+ godot_string a, b, c;
+ godot_string_new_with_latin1_chars(&a, "Test");
+ godot_string_new_with_latin1_chars(&b, "Test");
+ godot_string_new_with_latin1_chars(&c, "West");
+ CHECK(godot_string_hash(&a) == godot_string_hash(&b));
+ CHECK(godot_string_hash(&a) != godot_string_hash(&c));
+
+ CHECK(godot_string_hash64(&a) == godot_string_hash64(&b));
+ CHECK(godot_string_hash64(&a) != godot_string_hash64(&c));
+
+ godot_string_destroy(&a);
+ godot_string_destroy(&b);
+ godot_string_destroy(&c);
+}
+
+TEST_CASE("[GDNatvie String] http_escape/unescape") {
+ godot_string s, t, u;
+ godot_string_new_with_latin1_chars(&s, "Godot Engine:'docs'");
+ godot_string_new_with_latin1_chars(&t, "Godot%20Engine%3A%27docs%27");
+
+ u = godot_string_http_escape(&s);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
+ godot_string_destroy(&u);
+
+ u = godot_string_http_unescape(&t);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&s)) == 0);
+ godot_string_destroy(&u);
+
+ godot_string_destroy(&s);
+ godot_string_destroy(&t);
+}
+
+TEST_CASE("[GDNatvie String] percent_encode/decode") {
+ godot_string s, t, u;
+ godot_string_new_with_latin1_chars(&s, "Godot Engine:'docs'");
+ godot_string_new_with_latin1_chars(&t, "Godot%20Engine%3a%27docs%27");
+
+ u = godot_string_percent_encode(&s);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
+ godot_string_destroy(&u);
+
+ u = godot_string_percent_decode(&t);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&s)) == 0);
+ godot_string_destroy(&u);
+
+ godot_string_destroy(&s);
+ godot_string_destroy(&t);
+}
+
+TEST_CASE("[GDNatvie String] xml_escape/unescape") {
+ godot_string s, t, u;
+ godot_string_new_with_latin1_chars(&s, "\"Test\" <test@test&'test'>");
+
+ t = godot_string_xml_escape_with_quotes(&s);
+ u = godot_string_xml_unescape(&t);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&s)) == 0);
+ godot_string_destroy(&u);
+ godot_string_destroy(&t);
+
+ t = godot_string_xml_escape(&s);
+ u = godot_string_xml_unescape(&t);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&s)) == 0);
+ godot_string_destroy(&u);
+ godot_string_destroy(&t);
+
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Strip escapes") {
+ godot_string s, t, u;
+ godot_string_new_with_latin1_chars(&s, "\t\tTest Test\r\n Test");
+ godot_string_new_with_latin1_chars(&t, "Test Test Test");
+
+ u = godot_string_strip_escapes(&s);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
+ godot_string_destroy(&u);
+
+ godot_string_destroy(&t);
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Strip edges") {
+ godot_string s, t, u;
+ godot_string_new_with_latin1_chars(&s, "\t Test Test ");
+
+ godot_string_new_with_latin1_chars(&t, "Test Test ");
+ u = godot_string_strip_edges(&s, true, false);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
+ godot_string_destroy(&u);
+ godot_string_destroy(&t);
+
+ godot_string_new_with_latin1_chars(&t, "\t Test Test");
+ u = godot_string_strip_edges(&s, false, true);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
+ godot_string_destroy(&u);
+ godot_string_destroy(&t);
+
+ godot_string_new_with_latin1_chars(&t, "Test Test");
+ u = godot_string_strip_edges(&s, true, true);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
+ godot_string_destroy(&u);
+ godot_string_destroy(&t);
+
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Similarity") {
+ godot_string a, b, c;
+ godot_string_new_with_latin1_chars(&a, "Test");
+ godot_string_new_with_latin1_chars(&b, "West");
+ godot_string_new_with_latin1_chars(&c, "Toad");
+
+ CHECK(godot_string_similarity(&a, &b) > godot_string_similarity(&a, &c));
+
+ godot_string_destroy(&a);
+ godot_string_destroy(&b);
+ godot_string_destroy(&c);
+}
+
+TEST_CASE("[GDNatvie String] Trim") {
+ godot_string s, t, u, p;
+ godot_string_new_with_latin1_chars(&s, "aaaTestbbb");
+
+ godot_string_new_with_latin1_chars(&p, "aaa");
+ godot_string_new_with_latin1_chars(&t, "Testbbb");
+ u = godot_string_trim_prefix(&s, &p);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
+ godot_string_destroy(&u);
+ godot_string_destroy(&t);
+ godot_string_destroy(&p);
+
+ godot_string_new_with_latin1_chars(&p, "bbb");
+ godot_string_new_with_latin1_chars(&t, "aaaTest");
+ u = godot_string_trim_suffix(&s, &p);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
+ godot_string_destroy(&u);
+ godot_string_destroy(&t);
+ godot_string_destroy(&p);
+
+ godot_string_new_with_latin1_chars(&p, "Test");
+ u = godot_string_trim_suffix(&s, &p);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&s)) == 0);
+ godot_string_destroy(&u);
+ godot_string_destroy(&p);
+
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Right/Left") {
+ godot_string s, t, u;
+ godot_string_new_with_latin1_chars(&s, "aaaTestbbb");
+ // ^
+
+ godot_string_new_with_latin1_chars(&t, "tbbb");
+ u = godot_string_right(&s, 6);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
+ godot_string_destroy(&u);
+ godot_string_destroy(&t);
+
+ godot_string_new_with_latin1_chars(&t, "aaaTes");
+ u = godot_string_left(&s, 6);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
+ godot_string_destroy(&u);
+ godot_string_destroy(&t);
+
+ godot_string_destroy(&s);
+}
+
+TEST_CASE("[GDNatvie String] Repeat") {
+ godot_string t, u;
+ godot_string_new_with_latin1_chars(&t, "ab");
+
+ u = godot_string_repeat(&t, 4);
+ CHECK(u32scmp(godot_string_get_data(&u), U"abababab") == 0);
+ godot_string_destroy(&u);
+
+ godot_string_destroy(&t);
+}
+
+TEST_CASE("[GDNatvie String] SHA1/SHA256/MD5") {
+ godot_string s, t, sha1, sha256, md5;
+ godot_string_new_with_latin1_chars(&s, "Godot");
+ godot_string_new_with_latin1_chars(&sha1, "a1e91f39b9fce6a9998b14bdbe2aa2b39dc2d201");
+ static uint8_t sha1_buf[20] = {
+ 0xA1, 0xE9, 0x1F, 0x39, 0xB9, 0xFC, 0xE6, 0xA9, 0x99, 0x8B, 0x14, 0xBD, 0xBE, 0x2A, 0xA2, 0xB3,
+ 0x9D, 0xC2, 0xD2, 0x01
+ };
+ godot_string_new_with_latin1_chars(&sha256, "2a02b2443f7985d89d09001086ae3dcfa6eb0f55c6ef170715d42328e16e6cb8");
+ static uint8_t sha256_buf[32] = {
+ 0x2A, 0x02, 0xB2, 0x44, 0x3F, 0x79, 0x85, 0xD8, 0x9D, 0x09, 0x00, 0x10, 0x86, 0xAE, 0x3D, 0xCF,
+ 0xA6, 0xEB, 0x0F, 0x55, 0xC6, 0xEF, 0x17, 0x07, 0x15, 0xD4, 0x23, 0x28, 0xE1, 0x6E, 0x6C, 0xB8
+ };
+ godot_string_new_with_latin1_chars(&md5, "4a336d087aeb0390da10ee2ea7cb87f8");
+ static uint8_t md5_buf[16] = {
+ 0x4A, 0x33, 0x6D, 0x08, 0x7A, 0xEB, 0x03, 0x90, 0xDA, 0x10, 0xEE, 0x2E, 0xA7, 0xCB, 0x87, 0xF8
+ };
+
+ godot_packed_byte_array buf = godot_string_sha1_buffer(&s);
+ CHECK(memcmp(sha1_buf, godot_packed_byte_array_ptr(&buf), 20) == 0);
+ godot_packed_byte_array_destroy(&buf);
+
+ t = godot_string_sha1_text(&s);
+ CHECK(u32scmp(godot_string_get_data(&t), godot_string_get_data(&sha1)) == 0);
+ godot_string_destroy(&t);
+
+ buf = godot_string_sha256_buffer(&s);
+ CHECK(memcmp(sha256_buf, godot_packed_byte_array_ptr(&buf), 32) == 0);
+ godot_packed_byte_array_destroy(&buf);
+
+ t = godot_string_sha256_text(&s);
+ CHECK(u32scmp(godot_string_get_data(&t), godot_string_get_data(&sha256)) == 0);
+ godot_string_destroy(&t);
+
+ buf = godot_string_md5_buffer(&s);
+ CHECK(memcmp(md5_buf, godot_packed_byte_array_ptr(&buf), 16) == 0);
+ godot_packed_byte_array_destroy(&buf);
+
+ t = godot_string_md5_text(&s);
+ CHECK(u32scmp(godot_string_get_data(&t), godot_string_get_data(&md5)) == 0);
+ godot_string_destroy(&t);
+
+ godot_string_destroy(&s);
+ godot_string_destroy(&sha1);
+ godot_string_destroy(&sha256);
+ godot_string_destroy(&md5);
+}
+
+TEST_CASE("[GDNatvie String] Join") {
+ godot_string s, t, u;
+ godot_string_new_with_latin1_chars(&s, ", ");
+
+ godot_packed_string_array parts;
+ godot_packed_string_array_new(&parts);
+ godot_string_new_with_latin1_chars(&t, "One");
+ godot_packed_string_array_push_back(&parts, &t);
+ godot_string_destroy(&t);
+ godot_string_new_with_latin1_chars(&t, "B");
+ godot_packed_string_array_push_back(&parts, &t);
+ godot_string_destroy(&t);
+ godot_string_new_with_latin1_chars(&t, "C");
+ godot_packed_string_array_push_back(&parts, &t);
+ godot_string_destroy(&t);
+
+ godot_string_new_with_latin1_chars(&u, "One, B, C");
+ t = godot_string_join(&s, &parts);
+ CHECK(u32scmp(godot_string_get_data(&u), godot_string_get_data(&t)) == 0);
+ godot_string_destroy(&u);
+ godot_string_destroy(&t);
+
+ godot_string_destroy(&s);
+ godot_packed_string_array_destroy(&parts);
+}
+
+TEST_CASE("[GDNatvie String] Is_*") {
+ static const char *data[12] = { "-30", "100", "10.1", "10,1", "1e2", "1e-2", "1e2e3", "0xAB", "AB", "Test1", "1Test", "Test*1" };
+ static bool isnum[12] = { true, true, true, false, false, false, false, false, false, false, false, false };
+ static bool isint[12] = { true, true, false, false, false, false, false, false, false, false, false, false };
+ static bool ishex[12] = { true, true, false, false, true, false, true, false, true, false, false, false };
+ static bool ishex_p[12] = { false, false, false, false, false, false, false, true, false, false, false, false };
+ static bool isflt[12] = { true, true, true, false, true, true, false, false, false, false, false, false };
+ static bool isid[12] = { false, false, false, false, false, false, false, false, true, true, false, false };
+
+ for (int i = 0; i < 12; i++) {
+ godot_string s;
+ godot_string_new_with_latin1_chars(&s, data[i]);
+ CHECK(godot_string_is_numeric(&s) == isnum[i]);
+ CHECK(godot_string_is_valid_integer(&s) == isint[i]);
+ CHECK(godot_string_is_valid_hex_number(&s, false) == ishex[i]);
+ CHECK(godot_string_is_valid_hex_number(&s, true) == ishex_p[i]);
+ CHECK(godot_string_is_valid_float(&s) == isflt[i]);
+ CHECK(godot_string_is_valid_identifier(&s) == isid[i]);
+ godot_string_destroy(&s);
+ }
+}
+
+TEST_CASE("[GDNatvie String] humanize_size") {
+ godot_string s;
+
+ s = godot_string_humanize_size(1000);
+ CHECK(u32scmp(godot_string_get_data(&s), U"1000 B") == 0);
+ godot_string_destroy(&s);
+
+ s = godot_string_humanize_size(1025);
+ CHECK(u32scmp(godot_string_get_data(&s), U"1.00 KiB") == 0);
+ godot_string_destroy(&s);
+
+ s = godot_string_humanize_size(1025300);
+ CHECK(u32scmp(godot_string_get_data(&s), U"1001.2 KiB") == 0);
+ godot_string_destroy(&s);
+
+ s = godot_string_humanize_size(100523550);
+ CHECK(u32scmp(godot_string_get_data(&s), U"95.86 MiB") == 0);
+ godot_string_destroy(&s);
+
+ s = godot_string_humanize_size(5345555000);
+ CHECK(u32scmp(godot_string_get_data(&s), U"4.97 GiB") == 0);
+ godot_string_destroy(&s);
+}
+
+#endif
+
+} // namespace TestGDNativeString
+
+#endif // TEST_GDNATVIE_STRING_H
diff --git a/tests/test_macros.cpp b/tests/test_macros.cpp
new file mode 100644
index 0000000000..2317223b23
--- /dev/null
+++ b/tests/test_macros.cpp
@@ -0,0 +1,42 @@
+/*************************************************************************/
+/* test_macros.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#define DOCTEST_CONFIG_IMPLEMENT
+#include "test_macros.h"
+
+Map<String, TestFunc> *test_commands = nullptr;
+
+int register_test_command(String p_command, TestFunc p_function) {
+ if (!test_commands) {
+ test_commands = new Map<String, TestFunc>;
+ }
+ test_commands->insert(p_command, p_function);
+ return 0;
+}
diff --git a/tests/test_macros.h b/tests/test_macros.h
index 45ba8581dd..3486c68bb7 100644
--- a/tests/test_macros.h
+++ b/tests/test_macros.h
@@ -31,6 +31,9 @@
#ifndef TEST_MACROS_H
#define TEST_MACROS_H
+#include "core/map.h"
+#include "core/variant.h"
+
// See documentation for doctest at:
// https://github.com/onqtam/doctest/blob/master/doc/markdown/readme.md#reference
#include "thirdparty/doctest/doctest.h"
@@ -104,4 +107,17 @@ DOCTEST_STRINGIFY_VARIANT(PackedVector2Array);
DOCTEST_STRINGIFY_VARIANT(PackedVector3Array);
DOCTEST_STRINGIFY_VARIANT(PackedColorArray);
+// Register test commands to be launched from the command-line.
+// For instance: REGISTER_TEST_COMMAND("gdscript-parser" &test_parser_func).
+// Example usage: `godot --test gdscript-parser`.
+
+typedef void (*TestFunc)();
+extern Map<String, TestFunc> *test_commands;
+int register_test_command(String p_command, TestFunc p_function);
+
+#define REGISTER_TEST_COMMAND(m_command, m_function) \
+ DOCTEST_GLOBAL_NO_WARNINGS(DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_)) = \
+ register_test_command(m_command, m_function); \
+ DOCTEST_GLOBAL_NO_WARNINGS_END()
+
#endif // TEST_MACROS_H
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index 892cc26a51..d41581883a 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -36,7 +36,8 @@
#include "test_basis.h"
#include "test_class_db.h"
#include "test_color.h"
-#include "test_gdscript.h"
+#include "test_expression.h"
+#include "test_gdnative_string.h"
#include "test_gradient.h"
#include "test_gui.h"
#include "test_math.h"
@@ -55,40 +56,64 @@
#include "tests/test_macros.h"
int test_main(int argc, char *argv[]) {
+ bool run_tests = true;
+
+ // Convert arguments to Godot's command-line.
+ List<String> args;
+
+ for (int i = 0; i < argc; i++) {
+ args.push_back(String::utf8(argv[i]));
+ }
+ OS::get_singleton()->set_cmdline("", args);
+
+ // Run custom test tools.
+ if (test_commands) {
+ for (Map<String, TestFunc>::Element *E = test_commands->front(); E; E = E->next()) {
+ if (args.find(E->key())) {
+ const TestFunc &test_func = E->get();
+ test_func();
+ run_tests = false;
+ break;
+ }
+ }
+ if (!run_tests) {
+ delete test_commands;
+ return 0;
+ }
+ }
// Doctest runner.
doctest::Context test_context;
- List<String> valid_arguments;
+ List<String> test_args;
// Clean arguments of "--test" from the args.
- int argument_count = 0;
for (int x = 0; x < argc; x++) {
- if (strncmp(argv[x], "--test", 6) != 0) {
- valid_arguments.push_back(String(argv[x]));
- argument_count++;
+ String arg = String(argv[x]);
+ if (arg != "--test") {
+ test_args.push_back(arg);
}
}
// Convert Godot command line arguments back to standard arguments.
- char **args = new char *[valid_arguments.size()];
- for (int x = 0; x < valid_arguments.size(); x++) {
+ char **doctest_args = new char *[test_args.size()];
+ for (int x = 0; x < test_args.size(); x++) {
// Operation to convert Godot string to non wchar string.
- CharString cs = valid_arguments[x].utf8();
+ CharString cs = test_args[x].utf8();
const char *str = cs.get_data();
// Allocate the string copy.
- args[x] = new char[strlen(str) + 1];
+ doctest_args[x] = new char[strlen(str) + 1];
// Copy this into memory.
- std::memcpy(args[x], str, strlen(str) + 1);
+ memcpy(doctest_args[x], str, strlen(str) + 1);
}
- test_context.applyCommandLine(valid_arguments.size(), args);
+ test_context.applyCommandLine(test_args.size(), doctest_args);
test_context.setOption("order-by", "name");
test_context.setOption("abort-after", 5);
test_context.setOption("no-breaks", true);
- for (int x = 0; x < valid_arguments.size(); x++) {
- delete[] args[x];
+ for (int x = 0; x < test_args.size(); x++) {
+ delete[] doctest_args[x];
}
- delete[] args;
+ delete[] doctest_args;
return test_context.run();
}
diff --git a/tests/test_math.cpp b/tests/test_math.cpp
index 84a85be2f6..862535b57e 100644
--- a/tests/test_math.cpp
+++ b/tests/test_math.cpp
@@ -162,7 +162,7 @@ class GetClassAndNamespace {
} break;
case '\'':
case '"': {
- CharType begin_str = code[idx];
+ char32_t begin_str = code[idx];
idx++;
String tk_string = String();
while (true) {
@@ -176,13 +176,13 @@ class GetClassAndNamespace {
} else if (code[idx] == '\\') {
//escaped characters...
idx++;
- CharType next = code[idx];
+ char32_t next = code[idx];
if (next == 0) {
error_str = "Unterminated String";
error = true;
return TK_ERROR;
}
- CharType res = 0;
+ char32_t res = 0;
switch (next) {
case 'b':
@@ -241,7 +241,7 @@ class GetClassAndNamespace {
if (code[idx] == '-' || (code[idx] >= '0' && code[idx] <= '9')) {
//a number
- const CharType *rptr;
+ const char32_t *rptr;
double number = String::to_float(&code[idx], &rptr);
idx += (rptr - &code[idx]);
value = number;
diff --git a/tests/test_shader_lang.cpp b/tests/test_shader_lang.cpp
index 34ee3e3210..d363ee22b5 100644
--- a/tests/test_shader_lang.cpp
+++ b/tests/test_shader_lang.cpp
@@ -325,7 +325,7 @@ MainLoop *test() {
String code;
while (true) {
- CharType c = fa->get_8();
+ char32_t c = fa->get_8();
if (fa->eof_reached()) {
break;
}
diff --git a/tests/test_string.h b/tests/test_string.h
index 22019a64c6..b041cb2f49 100644
--- a/tests/test_string.h
+++ b/tests/test_string.h
@@ -48,36 +48,159 @@
namespace TestString {
-TEST_CASE("[String] Assign from cstr") {
+int u32scmp(const char32_t *l, const char32_t *r) {
+ for (; *l == *r && *l && *r; l++, r++)
+ ;
+ return *l - *r;
+}
+
+TEST_CASE("[String] Assign Latin-1 char string") {
String s = "Hello";
- CHECK(wcscmp(s.c_str(), L"Hello") == 0);
+ CHECK(u32scmp(s.get_data(), U"Hello") == 0);
}
-TEST_CASE("[String] Assign from string (operator=)") {
+TEST_CASE("[String] Assign from Latin-1 char string (operator=)") {
String s = "Dolly";
const String &t = s;
- CHECK(wcscmp(t.c_str(), L"Dolly") == 0);
+ CHECK(u32scmp(t.get_data(), U"Dolly") == 0);
}
-TEST_CASE("[String] Assign from c-string (copycon)") {
+TEST_CASE("[String] Assign from Latin-1 char string (copycon)") {
String s("Sheep");
- const String &t(s);
- CHECK(wcscmp(t.c_str(), L"Sheep") == 0);
+ const String &t1(s);
+ CHECK(u32scmp(t1.get_data(), U"Sheep") == 0);
+
+ String t2 = String("Sheep", 3);
+ CHECK(u32scmp(t2.get_data(), U"She") == 0);
}
-TEST_CASE("[String] Assign from c-widechar (operator=)") {
- String s(L"Give me");
- CHECK(wcscmp(s.c_str(), L"Give me") == 0);
+TEST_CASE("[String] Assign from wchar_t string (operator=)") {
+ String s = L"Give me";
+ CHECK(u32scmp(s.get_data(), U"Give me") == 0);
}
-TEST_CASE("[String] Assign from c-widechar (copycon)") {
+TEST_CASE("[String] Assign from wchar_t string (copycon)") {
String s(L"Wool");
- CHECK(wcscmp(s.c_str(), L"Wool") == 0);
+ CHECK(u32scmp(s.get_data(), U"Wool") == 0);
+}
+
+TEST_CASE("[String] Assign from char32_t string (operator=)") {
+ String s = U"Give me";
+ CHECK(u32scmp(s.get_data(), U"Give me") == 0);
+}
+
+TEST_CASE("[String] Assign from char32_t string (copycon)") {
+ String s(U"Wool");
+ CHECK(u32scmp(s.get_data(), U"Wool") == 0);
+}
+
+TEST_CASE("[String] UTF8") {
+ /* how can i embed UTF in here? */
+ static const char32_t u32str[] = { 0x0045, 0x0020, 0x304A, 0x360F, 0x3088, 0x3046, 0x1F3A4, 0 };
+ static const uint8_t u8str[] = { 0x45, 0x20, 0xE3, 0x81, 0x8A, 0xE3, 0x98, 0x8F, 0xE3, 0x82, 0x88, 0xE3, 0x81, 0x86, 0xF0, 0x9F, 0x8E, 0xA4, 0 };
+ String s = u32str;
+ bool err = s.parse_utf8(s.utf8().get_data());
+ CHECK(!err);
+ CHECK(s == u32str);
+
+ err = s.parse_utf8((const char *)u8str);
+ CHECK(!err);
+ CHECK(s == u32str);
+
+ CharString cs = (const char *)u8str;
+ CHECK(String::utf8(cs) == s);
+}
+
+TEST_CASE("[String] UTF16") {
+ /* how can i embed UTF in here? */
+ static const char32_t u32str[] = { 0x0045, 0x0020, 0x304A, 0x360F, 0x3088, 0x3046, 0x1F3A4, 0 };
+ static const char16_t u16str[] = { 0x0045, 0x0020, 0x304A, 0x360F, 0x3088, 0x3046, 0xD83C, 0xDFA4, 0 };
+ String s = u32str;
+ bool err = s.parse_utf16(s.utf16().get_data());
+ CHECK(!err);
+ CHECK(s == u32str);
+
+ err = s.parse_utf16(u16str);
+ CHECK(!err);
+ CHECK(s == u32str);
+
+ Char16String cs = u16str;
+ CHECK(String::utf16(cs) == s);
+}
+
+TEST_CASE("[String] UTF8 with BOM") {
+ /* how can i embed UTF in here? */
+ static const char32_t u32str[] = { 0x0045, 0x0020, 0x304A, 0x360F, 0x3088, 0x3046, 0x1F3A4, 0 };
+ static const uint8_t u8str[] = { 0xEF, 0xBB, 0xBF, 0x45, 0x20, 0xE3, 0x81, 0x8A, 0xE3, 0x98, 0x8F, 0xE3, 0x82, 0x88, 0xE3, 0x81, 0x86, 0xF0, 0x9F, 0x8E, 0xA4, 0 };
+ String s;
+ bool err = s.parse_utf8((const char *)u8str);
+ CHECK(!err);
+ CHECK(s == u32str);
+
+ CharString cs = (const char *)u8str;
+ CHECK(String::utf8(cs) == s);
+}
+
+TEST_CASE("[String] UTF16 with BOM") {
+ /* how can i embed UTF in here? */
+ static const char32_t u32str[] = { 0x0020, 0x0045, 0x304A, 0x360F, 0x3088, 0x3046, 0x1F3A4, 0 };
+ static const char16_t u16str[] = { 0xFEFF, 0x0020, 0x0045, 0x304A, 0x360F, 0x3088, 0x3046, 0xD83C, 0xDFA4, 0 };
+ static const char16_t u16str_swap[] = { 0xFFFE, 0x2000, 0x4500, 0x4A30, 0x0F36, 0x8830, 0x4630, 0x3CD8, 0xA4DF, 0 };
+ String s;
+ bool err = s.parse_utf16(u16str);
+ CHECK(!err);
+ CHECK(s == u32str);
+
+ err = s.parse_utf16(u16str_swap);
+ CHECK(!err);
+ CHECK(s == u32str);
+
+ Char16String cs = u16str;
+ CHECK(String::utf16(cs) == s);
+
+ cs = u16str_swap;
+ CHECK(String::utf16(cs) == s);
+}
+
+TEST_CASE("[String] Invalid UTF8") {
+ ERR_PRINT_OFF
+ static const uint8_t u8str[] = { 0x45, 0xE3, 0x81, 0x8A, 0x8F, 0xE3, 0xE3, 0x98, 0x8F, 0xE3, 0x82, 0x88, 0xE3, 0x81, 0x86, 0xF0, 0x9F, 0x8E, 0xA4, 0 };
+ String s;
+ bool err = s.parse_utf8((const char *)u8str);
+ CHECK(err);
+ CHECK(s == String());
+
+ CharString cs = (const char *)u8str;
+ CHECK(String::utf8(cs) == String());
+ ERR_PRINT_ON
+}
+
+TEST_CASE("[String] Invalid UTF16") {
+ ERR_PRINT_OFF
+ static const char16_t u16str[] = { 0x0045, 0x304A, 0x3088, 0x3046, 0xDFA4, 0 };
+ String s;
+ bool err = s.parse_utf16(u16str);
+ CHECK(err);
+ CHECK(s == String());
+
+ Char16String cs = u16str;
+ CHECK(String::utf16(cs) == String());
+ ERR_PRINT_ON
+}
+
+TEST_CASE("[String] ASCII") {
+ String s = U"Primero Leche";
+ String t = s.ascii(false).get_data();
+ CHECK(s == t);
+
+ t = s.ascii(true).get_data();
+ CHECK(s == t);
}
TEST_CASE("[String] Comparisons (equal)") {
String s = "Test Compare";
CHECK(s == "Test Compare");
+ CHECK(s == U"Test Compare");
CHECK(s == L"Test Compare");
CHECK(s == String("Test Compare"));
}
@@ -85,6 +208,7 @@ TEST_CASE("[String] Comparisons (equal)") {
TEST_CASE("[String] Comparisons (not equal)") {
String s = "Test Compare";
CHECK(s != "Peanut");
+ CHECK(s != U"Coconut");
CHECK(s != L"Coconut");
CHECK(s != String("Butter"));
}
@@ -92,6 +216,7 @@ TEST_CASE("[String] Comparisons (not equal)") {
TEST_CASE("[String] Comparisons (operator <)") {
String s = "Bees";
CHECK(s < "Elephant");
+ CHECK(!(s < U"Amber"));
CHECK(!(s < L"Amber"));
CHECK(!(s < String("Beatrix")));
}
@@ -103,7 +228,7 @@ TEST_CASE("[String] Concatenation") {
s += ' ';
s += 'a';
s += String(" ");
- s = s + L"Nice";
+ s = s + U"Nice";
s = s + " ";
s = s + String("Day");
@@ -130,34 +255,49 @@ TEST_CASE("[String] Testing for empty string") {
CHECK(String("").empty());
}
+TEST_CASE("[String] Test chr") {
+ CHECK(String::chr('H') == "H");
+ CHECK(String::chr(0x3012)[0] == 0x3012);
+ ERR_PRINT_OFF
+ CHECK(String::chr(0xd812)[0] == 0xfffd); // Unpaired UTF-16 surrogate
+ CHECK(String::chr(0x20d812)[0] == 0xfffd); // Outside UTF-32 range
+ ERR_PRINT_ON
+}
+
TEST_CASE("[String] Operator []") {
String a = "Kugar Sane";
a[0] = 'S';
a[6] = 'C';
CHECK(a == "Sugar Cane");
CHECK(a[1] == 'u');
+ CHECK(a.ord_at(1) == 'u');
}
TEST_CASE("[String] Case function test") {
String a = "MoMoNgA";
CHECK(a.to_upper() == "MOMONGA");
+ CHECK(a.to_lower() == "momonga");
+}
+
+TEST_CASE("[String] Case compare function test") {
+ String a = "MoMoNgA";
+
+ CHECK(a.casecmp_to("momonga") != 0);
CHECK(a.nocasecmp_to("momonga") == 0);
}
-TEST_CASE("[String] UTF8") {
- /* how can i embed UTF in here? */
- static const CharType ustr[] = { 0x304A, 0x360F, 0x3088, 0x3046, 0 };
- //static const wchar_t ustr[] = { 'P', 0xCE, 'p',0xD3, 0 };
- String s = ustr;
- s.parse_utf8(s.utf8().get_data());
- CHECK(s == ustr);
+TEST_CASE("[String] Natural compare function test") {
+ String a = "img2.png";
+
+ CHECK(a.nocasecmp_to("img10.png") > 0);
+ CHECK(a.naturalnocasecmp_to("img10.png") < 0);
}
-TEST_CASE("[String] ASCII") {
- String s = L"Primero Leche";
- String t = s.ascii().get_data();
- CHECK(s == t);
+TEST_CASE("[String] hex_encode_buffer") {
+ static const uint8_t u8str[] = { 0x45, 0xE3, 0x81, 0x8A, 0x8F, 0xE3 };
+ String s = String::hex_encode_buffer(u8str, 6);
+ CHECK(s == U"45e3818a8fe3");
}
TEST_CASE("[String] Substr") {
@@ -165,24 +305,45 @@ TEST_CASE("[String] Substr") {
CHECK(s.substr(3, 4) == "ler ");
}
-TEST_CASE("[string] Find") {
- String s = "Pretty Woman";
- s.find("Revenge of the Monster Truck");
-
+TEST_CASE("[String] Find") {
+ String s = "Pretty Woman Woman";
CHECK(s.find("tty") == 3);
+ CHECK(s.find("Wo", 9) == 13);
CHECK(s.find("Revenge of the Monster Truck") == -1);
+ CHECK(s.rfind("man") == 15);
}
-TEST_CASE("[String] find no case") {
- String s = "Pretty Whale";
+TEST_CASE("[String] Find no case") {
+ String s = "Pretty Whale Whale";
CHECK(s.findn("WHA") == 7);
+ CHECK(s.findn("WHA", 9) == 13);
CHECK(s.findn("Revenge of the Monster SawFish") == -1);
+ CHECK(s.rfindn("WHA") == 13);
+}
+
+TEST_CASE("[String] Find MK") {
+ Vector<String> keys;
+ keys.push_back("sty");
+ keys.push_back("tty");
+ keys.push_back("man");
+
+ String s = "Pretty Woman";
+ int key = 0;
+
+ CHECK(s.findmk(keys, 0, &key) == 3);
+ CHECK(key == 1);
+
+ CHECK(s.findmk(keys, 5, &key) == 9);
+ CHECK(key == 2);
}
TEST_CASE("[String] Find and replace") {
String s = "Happy Birthday, Anna!";
s = s.replace("Birthday", "Halloween");
CHECK(s == "Happy Halloween, Anna!");
+
+ s = s.replace_first("H", "W");
+ CHECK(s == "Wappy Halloween, Anna!");
}
TEST_CASE("[String] Insertion") {
@@ -193,6 +354,12 @@ TEST_CASE("[String] Insertion") {
TEST_CASE("[String] Number to string") {
CHECK(String::num(3.141593) == "3.141593");
+ CHECK(String::num(3.141593, 3) == "3.142");
+ CHECK(String::num_real(3.141593) == "3.141593");
+ CHECK(String::num_scientific(30000000) == "3e+07");
+ CHECK(String::num_int64(3141593) == "3141593");
+ CHECK(String::num_int64(0xA141593, 16) == "a141593");
+ CHECK(String::num_int64(0xA141593, 16, true) == "A141593");
}
TEST_CASE("[String] String to integer") {
@@ -204,6 +371,18 @@ TEST_CASE("[String] String to integer") {
}
}
+TEST_CASE("[String] Hex to integer") {
+ static const char *nums[4] = { "0xFFAE", "22", "0", "AADDAD" };
+ static const int64_t num[4] = { 0xFFAE, 0x22, 0, 0xAADDAD };
+ static const bool wo_prefix[4] = { false, true, true, true };
+ static const bool w_prefix[4] = { true, false, true, false };
+
+ for (int i = 0; i < 4; i++) {
+ CHECK((String(nums[i]).hex_to_int(true) == num[i]) == w_prefix[i]);
+ CHECK((String(nums[i]).hex_to_int(false) == num[i]) == wo_prefix[i]);
+ }
+}
+
TEST_CASE("[String] String to float") {
static const char *nums[4] = { "-12348298412.2", "0.05", "2.0002", " -0.0001" };
static const double num[4] = { -12348298412.2, 0.05, 2.0002, -0.0001 };
@@ -213,6 +392,11 @@ TEST_CASE("[String] String to float") {
}
}
+TEST_CASE("[String] CamelCase to underscore") {
+ CHECK(String("TestTestStringGD").camelcase_to_underscore(false) == String("Test_Test_String_GD"));
+ CHECK(String("TestTestStringGD").camelcase_to_underscore(true) == String("test_test_string_gd"));
+}
+
TEST_CASE("[String] Slicing") {
String s = "Mars,Jupiter,Saturn,Uranus";
@@ -222,6 +406,69 @@ TEST_CASE("[String] Slicing") {
}
}
+TEST_CASE("[String] Splitting") {
+ String s = "Mars,Jupiter,Saturn,Uranus";
+ Vector<String> l;
+
+ const char *slices_l[3] = { "Mars", "Jupiter", "Saturn,Uranus" };
+ const char *slices_r[3] = { "Mars,Jupiter", "Saturn", "Uranus" };
+
+ l = s.split(",", true, 2);
+ CHECK(l.size() == 3);
+ for (int i = 0; i < l.size(); i++) {
+ CHECK(l[i] == slices_l[i]);
+ }
+
+ l = s.rsplit(",", true, 2);
+ CHECK(l.size() == 3);
+ for (int i = 0; i < l.size(); i++) {
+ CHECK(l[i] == slices_r[i]);
+ }
+
+ s = "Mars Jupiter Saturn Uranus";
+ const char *slices_s[4] = { "Mars", "Jupiter", "Saturn", "Uranus" };
+ l = s.split_spaces();
+ for (int i = 0; i < l.size(); i++) {
+ CHECK(l[i] == slices_s[i]);
+ }
+
+ s = "1.2;2.3 4.5";
+ const double slices_d[3] = { 1.2, 2.3, 4.5 };
+
+ Vector<float> f;
+ f = s.split_floats(";");
+ CHECK(f.size() == 2);
+ for (int i = 0; i < f.size(); i++) {
+ CHECK(ABS(f[i] - slices_d[i]) <= 0.00001);
+ }
+
+ Vector<String> keys;
+ keys.push_back(";");
+ keys.push_back(" ");
+
+ f = s.split_floats_mk(keys);
+ CHECK(f.size() == 3);
+ for (int i = 0; i < f.size(); i++) {
+ CHECK(ABS(f[i] - slices_d[i]) <= 0.00001);
+ }
+
+ s = "1;2 4";
+ const int slices_i[3] = { 1, 2, 4 };
+
+ Vector<int> ii;
+ ii = s.split_ints(";");
+ CHECK(ii.size() == 2);
+ for (int i = 0; i < ii.size(); i++) {
+ CHECK(ii[i] == slices_i[i]);
+ }
+
+ ii = s.split_ints_mk(keys);
+ CHECK(ii.size() == 3);
+ for (int i = 0; i < ii.size(); i++) {
+ CHECK(ii[i] == slices_i[i]);
+ }
+}
+
TEST_CASE("[String] Erasing") {
String s = "Josephine is such a cute girl!";
s.erase(s.find("cute "), String("cute ").length());
@@ -239,7 +486,7 @@ TEST_CASE("[String] Regex substitution") {
struct test_27_data {
char const *data;
- char const *begin;
+ char const *part;
bool expected;
};
@@ -253,9 +500,9 @@ TEST_CASE("[String] Begins with") {
bool state = true;
for (size_t i = 0; state && i < count; ++i) {
String s = tc[i].data;
- state = s.begins_with(tc[i].begin) == tc[i].expected;
+ state = s.begins_with(tc[i].part) == tc[i].expected;
if (state) {
- String sb = tc[i].begin;
+ String sb = tc[i].part;
state = s.begins_with(sb) == tc[i].expected;
}
CHECK(state);
@@ -266,6 +513,42 @@ TEST_CASE("[String] Begins with") {
CHECK(state);
}
+TEST_CASE("[String] Ends with") {
+ test_27_data tc[] = {
+ { "res://foobar", "foobar", true },
+ { "res", "res://", false },
+ { "abc", "abc", true }
+ };
+ size_t count = sizeof(tc) / sizeof(tc[0]);
+ bool state = true;
+ for (size_t i = 0; state && i < count; ++i) {
+ String s = tc[i].data;
+ state = s.ends_with(tc[i].part) == tc[i].expected;
+ if (state) {
+ String sb = tc[i].part;
+ state = s.ends_with(sb) == tc[i].expected;
+ }
+ CHECK(state);
+ if (!state) {
+ break;
+ }
+ };
+ CHECK(state);
+}
+
+TEST_CASE("[String] format") {
+ const String value_format = "red=\"$red\" green=\"$green\" blue=\"$blue\" alpha=\"$alpha\"";
+
+ Dictionary value_dictionary;
+ value_dictionary["red"] = 10;
+ value_dictionary["green"] = 20;
+ value_dictionary["blue"] = "bla";
+ value_dictionary["alpha"] = 0.4;
+ String value = value_format.format(value_dictionary, "$_");
+
+ CHECK(value == "red=\"10\" green=\"20\" blue=\"bla\" alpha=\"0.4\"");
+}
+
TEST_CASE("[String] sprintf") {
String format, output;
Array args;
@@ -560,6 +843,38 @@ TEST_CASE("[String] sprintf") {
CHECK(output == "%c requires number or single-character string");
}
+TEST_CASE("[String] is_numeric") {
+ CHECK(String("12").is_numeric());
+ CHECK(String("1.2").is_numeric());
+ CHECK(!String("AF").is_numeric());
+ CHECK(String("-12").is_numeric());
+ CHECK(String("-1.2").is_numeric());
+}
+
+TEST_CASE("[String] pad") {
+ String s = String("test");
+ CHECK(s.lpad(10, "x") == U"xxxxxxtest");
+ CHECK(s.rpad(10, "x") == U"testxxxxxx");
+
+ s = String("10.10");
+ CHECK(s.pad_decimals(4) == U"10.1000");
+ CHECK(s.pad_zeros(4) == U"0010.10");
+}
+
+TEST_CASE("[String] is_subsequence_of") {
+ String a = "is subsequence of";
+ CHECK(String("sub").is_subsequence_of(a));
+ CHECK(!String("Sub").is_subsequence_of(a));
+ CHECK(String("Sub").is_subsequence_ofi(a));
+}
+
+TEST_CASE("[String] match") {
+ CHECK(String("img1.png").match("*.png"));
+ CHECK(!String("img1.jpeg").match("*.png"));
+ CHECK(!String("img1.Png").match("*.png"));
+ CHECK(String("img1.Png").matchn("*.png"));
+}
+
TEST_CASE("[String] IPVX address to string") {
IP_Address ip0("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
IP_Address ip(0x0123, 0x4567, 0x89ab, 0xcdef, true);
@@ -792,7 +1107,196 @@ TEST_CASE("[String] Count and countn functionality") {
COUNT_TEST(String("testTest-TeStatest").countn("tEsT", 4, 16) == 2);
CHECK(state);
+
+#undef COUNT_TEST
+}
+
+TEST_CASE("[String] Bigrams") {
+ String s = "abcd";
+ Vector<String> bigr = s.bigrams();
+
+ CHECK(bigr.size() == 3);
+ CHECK(bigr[0] == "ab");
+ CHECK(bigr[1] == "bc");
+ CHECK(bigr[2] == "cd");
+}
+
+TEST_CASE("[String] c-escape/unescape") {
+ String s = "\\1\a2\b\f3\n45\r6\t7\v8\'9\?0\"";
+ CHECK(s.c_escape().c_unescape() == s);
+}
+
+TEST_CASE("[String] dedent") {
+ String s = " aaa\n bbb";
+ String t = "aaa\nbbb";
+ CHECK(s.dedent() == t);
+}
+
+TEST_CASE("[String] Path functions") {
+ static const char *path[4] = { "C:\\Godot\\project\\test.tscn", "/Godot/project/test.xscn", "../Godot/project/test.scn", "Godot\\test.doc" };
+ static const char *base_dir[4] = { "C:\\Godot\\project", "/Godot/project", "../Godot/project", "Godot" };
+ static const char *base_name[4] = { "C:\\Godot\\project\\test", "/Godot/project/test", "../Godot/project/test", "Godot\\test" };
+ static const char *ext[4] = { "tscn", "xscn", "scn", "doc" };
+ static const char *file[4] = { "test.tscn", "test.xscn", "test.scn", "test.doc" };
+ static const bool abs[4] = { true, true, false, false };
+
+ for (int i = 0; i < 4; i++) {
+ CHECK(String(path[i]).get_base_dir() == base_dir[i]);
+ CHECK(String(path[i]).get_basename() == base_name[i]);
+ CHECK(String(path[i]).get_extension() == ext[i]);
+ CHECK(String(path[i]).get_file() == file[i]);
+ CHECK(String(path[i]).is_abs_path() == abs[i]);
+ CHECK(String(path[i]).is_rel_path() != abs[i]);
+ CHECK(String(path[i]).simplify_path().get_base_dir().plus_file(file[i]) == String(path[i]).simplify_path());
+ }
+
+ static const char *file_name[3] = { "test.tscn", "test://.xscn", "?tes*t.scn" };
+ static const bool valid[3] = { true, false, false };
+ for (int i = 0; i < 3; i++) {
+ CHECK(String(file_name[i]).is_valid_filename() == valid[i]);
+ }
+}
+
+TEST_CASE("[String] hash") {
+ String a = "Test";
+ String b = "Test";
+ String c = "West";
+ CHECK(a.hash() == b.hash());
+ CHECK(a.hash() != c.hash());
+
+ CHECK(a.hash64() == b.hash64());
+ CHECK(a.hash64() != c.hash64());
+}
+
+TEST_CASE("[String] http_escape/unescape") {
+ String s = "Godot Engine:'docs'";
+ String t = "Godot%20Engine%3A%27docs%27";
+
+ CHECK(s.http_escape() == t);
+ CHECK(t.http_unescape() == s);
+}
+
+TEST_CASE("[String] percent_encode/decode") { // Note: is it redundant? Seems to be same as http_escape/unescape but in lower case.
+ String s = "Godot Engine:'docs'";
+ String t = "Godot%20Engine%3a%27docs%27";
+
+ CHECK(s.percent_encode() == t);
+ CHECK(t.percent_decode() == s);
+}
+
+TEST_CASE("[String] xml_escape/unescape") {
+ String s = "\"Test\" <test@test&'test'>";
+ CHECK(s.xml_escape(true).xml_unescape() == s);
+ CHECK(s.xml_escape(false).xml_unescape() == s);
+}
+
+TEST_CASE("[String] Strip escapes") {
+ String s = "\t\tTest Test\r\n Test";
+ CHECK(s.strip_escapes() == "Test Test Test");
}
+
+TEST_CASE("[String] Similarity") {
+ String a = "Test";
+ String b = "West";
+ String c = "Toad";
+ CHECK(a.similarity(b) > a.similarity(c));
+}
+
+TEST_CASE("[String] Strip edges") {
+ String s = "\t Test Test ";
+ CHECK(s.strip_edges(true, false) == "Test Test ");
+ CHECK(s.strip_edges(false, true) == "\t Test Test");
+ CHECK(s.strip_edges(true, true) == "Test Test");
+}
+
+TEST_CASE("[String] Trim") {
+ String s = "aaaTestbbb";
+ CHECK(s.trim_prefix("aaa") == "Testbbb");
+ CHECK(s.trim_suffix("bbb") == "aaaTest");
+ CHECK(s.trim_suffix("Test") == s);
+}
+
+TEST_CASE("[String] Right/Left") {
+ String s = "aaaTestbbb";
+ // ^
+ CHECK(s.right(6) == "tbbb");
+ CHECK(s.left(6) == "aaaTes");
+}
+
+TEST_CASE("[String] Repeat") {
+ String s = "abababab";
+ String x = "ab";
+ String t = x.repeat(4);
+ CHECK(t == s);
+}
+
+TEST_CASE("[String] SHA1/SHA256/MD5") {
+ String s = "Godot";
+ String sha1 = "a1e91f39b9fce6a9998b14bdbe2aa2b39dc2d201";
+ static uint8_t sha1_buf[20] = {
+ 0xA1, 0xE9, 0x1F, 0x39, 0xB9, 0xFC, 0xE6, 0xA9, 0x99, 0x8B, 0x14, 0xBD, 0xBE, 0x2A, 0xA2, 0xB3,
+ 0x9D, 0xC2, 0xD2, 0x01
+ };
+ String sha256 = "2a02b2443f7985d89d09001086ae3dcfa6eb0f55c6ef170715d42328e16e6cb8";
+ static uint8_t sha256_buf[32] = {
+ 0x2A, 0x02, 0xB2, 0x44, 0x3F, 0x79, 0x85, 0xD8, 0x9D, 0x09, 0x00, 0x10, 0x86, 0xAE, 0x3D, 0xCF,
+ 0xA6, 0xEB, 0x0F, 0x55, 0xC6, 0xEF, 0x17, 0x07, 0x15, 0xD4, 0x23, 0x28, 0xE1, 0x6E, 0x6C, 0xB8
+ };
+ String md5 = "4a336d087aeb0390da10ee2ea7cb87f8";
+ static uint8_t md5_buf[16] = {
+ 0x4A, 0x33, 0x6D, 0x08, 0x7A, 0xEB, 0x03, 0x90, 0xDA, 0x10, 0xEE, 0x2E, 0xA7, 0xCB, 0x87, 0xF8
+ };
+
+ PackedByteArray buf = s.sha1_buffer();
+ CHECK(memcmp(sha1_buf, buf.ptr(), 20) == 0);
+ CHECK(s.sha1_text() == sha1);
+
+ buf = s.sha256_buffer();
+ CHECK(memcmp(sha256_buf, buf.ptr(), 32) == 0);
+ CHECK(s.sha256_text() == sha256);
+
+ buf = s.md5_buffer();
+ CHECK(memcmp(md5_buf, buf.ptr(), 16) == 0);
+ CHECK(s.md5_text() == md5);
+}
+
+TEST_CASE("[String] Join") {
+ String s = ", ";
+ Vector<String> parts;
+ parts.push_back("One");
+ parts.push_back("B");
+ parts.push_back("C");
+ String t = s.join(parts);
+ CHECK(t == "One, B, C");
+}
+
+TEST_CASE("[String] Is_*") {
+ static const char *data[12] = { "-30", "100", "10.1", "10,1", "1e2", "1e-2", "1e2e3", "0xAB", "AB", "Test1", "1Test", "Test*1" };
+ static bool isnum[12] = { true, true, true, false, false, false, false, false, false, false, false, false };
+ static bool isint[12] = { true, true, false, false, false, false, false, false, false, false, false, false };
+ static bool ishex[12] = { true, true, false, false, true, false, true, false, true, false, false, false };
+ static bool ishex_p[12] = { false, false, false, false, false, false, false, true, false, false, false, false };
+ static bool isflt[12] = { true, true, true, false, true, true, false, false, false, false, false, false };
+ static bool isid[12] = { false, false, false, false, false, false, false, false, true, true, false, false };
+ for (int i = 0; i < 12; i++) {
+ String s = String(data[i]);
+ CHECK(s.is_numeric() == isnum[i]);
+ CHECK(s.is_valid_integer() == isint[i]);
+ CHECK(s.is_valid_hex_number(false) == ishex[i]);
+ CHECK(s.is_valid_hex_number(true) == ishex_p[i]);
+ CHECK(s.is_valid_float() == isflt[i]);
+ CHECK(s.is_valid_identifier() == isid[i]);
+ }
+}
+
+TEST_CASE("[String] humanize_size") {
+ CHECK(String::humanize_size(1000) == "1000 B");
+ CHECK(String::humanize_size(1025) == "1.00 KiB");
+ CHECK(String::humanize_size(1025300) == "1001.2 KiB");
+ CHECK(String::humanize_size(100523550) == "95.86 MiB");
+ CHECK(String::humanize_size(5345555000) == "4.97 GiB");
+}
+
} // namespace TestString
#endif // TEST_STRING_H